How to compare the current row with next and previous row in PostgreSQL?
我想知道如何在SQL查询中与下一行或上一行进行逻辑比较来检索结果。我正在使用PostgreSQL。
示例
假设我的数据库中有一个具有两个属性(有序位置和随机数)的表,我想检索介于偶数之间的奇数。我该怎么办?
实际用法
我想找到两个其他单词之间的单词,这些单词的类别为NAME(并且该单词不是名称)。排序由句子和位置提供。
编辑
我想知道PostgreSQL的Window函数是否比查询更能解决此类问题。我听说过它们,但从未使用过。
这是我使用
1 2 3 4 5 6 7 8 9 10 11 12 13 | SELECT tokcat.text FROM ( SELECT text, category, chartype, lag(category,1) OVER w AS previousCategory, lead(category,1) OVER w AS nextCategory FROM token t, textBlockHasToken tb WHERE tb.tokenId = t.id WINDOW w AS ( PARTITION BY textBlockId, sentence ORDER BY textBlockId, sentence, POSITION ) ) tokcat WHERE 'NAME' = ANY(previousCategory) AND 'NAME' = ANY(nextCategory) AND 'NAME' <> ANY(category) |
简化版:
1 2 3 4 5 6 7 8 9 10 11 12 13 | SELECT text FROM ( SELECT text ,category ,lag(category) OVER w AS previous_cat ,lead(category) OVER w AS next_cat FROM token t JOIN textblockhastoken tb ON tb.tokenid = t.id WINDOW w AS (PARTITION BY textblockid, sentence ORDER BY POSITION) ) tokcat WHERE category <> 'NAME' AND previous_cat = 'NAME' AND next_cat = 'NAME'; |
要点
-
不需要
= ANY() ,窗口函数将返回单个值 - 子查询中的一些冗余字段
-
无需按列排序,您
PARTITION BY -ORDER BY适用于分区 - 不要在不加引号的情况下使用大小写混合的标识符,这只会导致混乱。 (更好的是:从未在PostgreSQL中使用大小写混合的标识符)
您可以在以下地址找到最佳解决方案:
http://blog.sqlauthority.com/2013/09/25/sql-server-how-to-access-the-previous-row-and-next-row-value-in-select-statement-part -4 /
查询1以获取SQL Server 2012及更高版本:
1 2 3 4 5 6 | SELECT LAG(p.FirstName) OVER(ORDER BY p.BusinessEntityID) PreviousValue, p.FirstName, LEAD(p.FirstName) OVER(ORDER BY p.BusinessEntityID) NextValue FROM Person.Person p GO |
SQL Server 2005和更高版本的查询2:
1 2 3 4 5 6 7 8 9 10 11 12 | WITH CTE AS( SELECT rownum = ROW_NUMBER() OVER(ORDER BY p.BusinessEntityID), p.FirstName FROM Person.Person p ) SELECT prev.FirstName PreviousValue, CTE.FirstName, nex.FirstName NextValue FROM CTE LEFT JOIN CTE prev ON prev.rownum = CTE.rownum - 1 LEFT JOIN CTE nex ON nex.rownum = CTE.rownum + 1 GO |
这应该起作用:
1 2 3 4 5 6 7 8 9 | SELECT w1.word AS word_before, w.word, w2.word AS word_after FROM word w JOIN word w1 USING (sentence) JOIN word w2 USING (sentence) WHERE w.category <> 'name' AND w1.pos = (w.pos - 1) AND w1.category = 'name' AND w2.pos = (w.pos + 1) AND w2.category = 'name' |
- 使用两个自联接
- 所有单词都必须在同一句子(?)中并按顺序排列。
- 之前的单词和之后的单词必须属于"名称"类别。单词本身不是"名称"
-
假定类别
IS NOT NULL
要回答您的附加问题:不,在这种情况下,窗口函数不是特别有用,自连接是此处的魔术词。 strike>
编辑:
我站得住了。 Renato通过窗口函数lag()和lead()演示了一个很酷的解决方案。
请注意细微的差异:
-
自联接对绝对值进行操作:如果缺少
pos -1 的行,则pos 的行不符合条件。 -
具有
lag() 和lead() 的Renatos版本在ORDER BY 创建的行的相对位置上运行。
在许多情况下(例如可能在手头吗?),两种版本均会导致相同的结果。 id空间中的间隙将导致不同的结果。