如何将当前行与PostgreSQL中的下一行和上一行进行比较?

时间:2011-11-02 01:32:25

标签: sql postgresql window

我想知道如何在SQL查询中检索结果,与下一行或上一行进行一些逻辑比较。我正在使用PostgreSQL。

示例
假设我的数据库中有一个表有两个属性(有序位置和随机数),我想检索偶数之间的奇数。我怎么能这样做?

真实用途
我想找到两个具有NAME类别的单词之间的单词(而单词不是名称)。订购由句子和位置提供。

修改 我想知道PostgreSQL的Window函数是否是解决这类问题的最佳解决方案。我听说过它们,但从未使用过。

3 个答案:

答案 0 :(得分:39)

这是我使用WINDOW functions的解决方案。我使用了laglead函数。两者都从与当前行偏移的行中的列返回值。 lag返回,lead在偏移中接下来。

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)

简化版:

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中使用混合大小写标识符永远

答案 1 :(得分:5)

您可以在此地址找到最佳解决方案:

http://blog.sqlauthority.com/2013/09/25/sql-server-how-to-access-the-previous-row-and-next-row-value-in-select-statement-part-4/

SQL Server 2012及更高版本的查询1:

square

SQL Server 2005+及更高版本的查询2:

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

答案 2 :(得分:2)

这应该有效:

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'
  • 使用两个自联接
  • 所有单词必须在同一个句子(?)和顺序中。
  • 之前的单词和之后的单词必须属于'name'类别。字本身不是'名字'
  • 这假定类别为IS NOT NULL

要回答你的其他问题:不,在这种情况下,窗口函数不是特别有用,自我加入是这里的神奇词。

编辑:
我纠正了。 Renato使用窗口函数lag() and lead()演示了一个很酷的解决方案 请注意细微差别:

  • 自我加入对绝对值进行操作:如果缺少pos -1的行,则pos的行不符合条件。
  • 带有lag()lead()的Renatos版本对ORDER BY创建的行的相对位置进行操作。

在许多情况下(可能在手头的那个?)两个版本都会产生相同的结果。由于id空间存在差异,因此会有不同的结果。