Как сравнить текущую строку со следующей и предыдущей строкой в ​​PostgreSQL? - PullRequest
21 голосов
/ 02 ноября 2011

Я хочу знать, как получить результаты в запросе SQL, выполнив некоторое логическое сравнение со следующей или предыдущей строкой.Я использую PostgreSQL.

Пример
Предположим, у меня есть таблица в моей базе данных с двумя атрибутами (упорядоченная позиция и случайные числа), я хочу получить нечетные числа, которые являютсямежду четными числами.Как я могу это сделать?

Реальное использование
Я хочу найти слова, которые находятся между двумя другими словами, которые имеют категорию ИМЯ (и это слово не является именем).Порядок обеспечивается предложением и позицией.

Редактировать Я хочу знать, является ли оконная функция PostgreSQL лучшим решением для такого рода проблем, чем выполнение запросов.Я слышал о них, но никогда не использовал.

Ответы [ 3 ]

41 голосов
/ 02 ноября 2011

Это мое решение с использованием WINDOW functions.Я использовал функции lag и lead.Оба возвращают значение из столбца из строки в смещении от текущей строки.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 ever )
5 голосов
/ 09 августа 2016

Лучшее решение вы можете найти по этому адресу:

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 и более поздних версий:

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 для SQL Server 2005+ и более поздних версий:

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
2 голосов
/ 02 ноября 2011

Это должно работать:

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

Чтобы ответить на ваш дополнительный вопрос: нет, оконная функция не будет особенно полезна в этом случае, self-join - магическое слово здесь.

Edit:
Я стою исправлено. Ренато демонстрирует классное решение с оконными функциями lag () и lead () .
Обратите внимание на тонкие различия:

  • Самостоятельные объединения работают на абсолютных значениях : если строка с pos -1 отсутствует, то строка с pos не подходит.
  • Версия Renatos с lag() и lead() работает на относительной позиции строк , созданной ORDER BY.

Во многих случаях (как, вероятно, в одной под рукой?) Обе версии приводят к одинаковым результатам. С пробелами в пространстве идентификаторов будут разные результаты.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...