【发布时间】:2018-09-07 14:35:48
【问题描述】:
根据PostgreSQL: detecting the first/last rows of result set,我有理由怀疑这样的条款是危险的或不合适的,并希望更好地理解这一点。采取:
SELECT last_value(unique_column) OVER (), * FROM mytable;
unique_column 是唯一的且不为空。那么以这种方式使用OVER ()有什么问题呢?它危险/不可靠吗?次优?据我所知,这应该返回结果集中最后一行的值——至少,当我尝试过它时。有人告诉我“最后”没有排序就没有意义,但显然有最后一行被返回。我还被告知OVER () 的意思是“任何事情都会发生”,这表明结果是不可靠的,但到目前为止,每次我运行这种查询时,我一直从最后得到值结果集。
现在如果我使用ORDER BY,我已经发现了一个问题:
SELECT last_value(unique_column) OVER (), * FROM mytable ORDER BY something_else;
但是,我的解决方案是子查询:
SELECT last_value(unique_column) OVER (), * FROM (SELECT * FROM mytable ORDER BY something_else) sub;
好像OVER () 表示分析函数(如first_value() 和last_value())根据引擎发生读取表/子查询的顺序运行。而且,据我所知,您可以充分控制引擎读取表/子查询的顺序(无需进行不必要的排序)。
我在 Debian 9.5 环境中运行 PostgreSQL 9.6。
【问题讨论】:
-
你只是走运了。永远不能保证您的数据每次都以相同的顺序从磁盘中提取。这不仅仅是“从表或子查询中提取引擎”这实际上是从驱动器上的数据块中提取的 postgres 实例。如果您考虑整个数据库堆栈将长期保持一致,那么您就是在玩火。在 SQL 中明确表达也是一种很好的做法。你知道你想要的顺序,你的数据库不知道。告诉它。
-
如果您不关心订单,您也可以使用
first_value() -
或者同样,如果您不关心
select myfield from mytable limit 1,我们实际上是在谈论仅获得一条记录时可以忽略不计的性能。 -
真棒@Opux 如果您不关心订单,那么您就是黄金。如果你真的想要结果集中的最后一项,那是 100% 完美的。我无法想象这样的场景是有意义的,但它在逻辑上是一致的,并且可以执行您希望它执行的操作:) 窗口函数在检索结果集后对其进行操作(这是处理的最后一步),所以这将随心所欲地工作。
-
@JNevill 正如我试图在链接中解释的那样,我需要那些分析函数来获取结果集中的第一条和最后一条记录来标识自己,所以我使用的表达式更接近
last_value(unique_column) OVER () = unique_column last_row_in_result_set.这是我们过去在 C++ 中处理的事情(很简单:只需在检索行的循环的开头和结尾标记它),但我们正试图将此类功能从 C++ 移动到 SQL。因此,直到我明白为什么结果集中间的一行可以被标记为最后一行,我才会这样做。谢谢。
标签: postgresql window-functions