sql: первая строка после последней строки со свойством

Я хотел бы написать запрос, который возвращает первую строку сразу после последней строки с заданным свойством (упорядоченным по идентификатору). Идентификаторы не могут быть последовательными.

В идеале это выглядело бы примерно так:

...
JOIN (select max(id) id from my_table where CONDITION) m
JOIN (select min(id) from my_table where id > m.id) n

Однако я не могу использовать идентификатор m во втором подзапросе.

Можно использовать вложенные запросы во вложенных запросах, но есть ли более простой способ?

Спасибо.


person erdos    schedule 20.12.2019    source источник
comment
Определить проще ... Трудно сказать, не видя всей картины.   -  person jarlh    schedule 20.12.2019
comment
Добавьте образцы данных с ожидаемым результатом (по порядку)   -  person mkRabbani    schedule 20.12.2019


Ответы (3)


Вы можете использовать lead(), чтобы получить следующий идентификатор перед применением условия:

select t.*
from my_table t join
     (select max(next_id) as max_next_id
      from (select t.*, lead(id) over (order by id) as next_id
            from my_table t
           ) t
      where <condition>
     ) tt
     on t.id = tt.max_next_id;

Вы также можете:

select t.*
from my_table t
where t.id > (select max(t2.id) from my_table t2 where <condition>)
order by t2.id asc
fetch first 1 row only;
person Gordon Linoff    schedule 20.12.2019
comment
немного сбивает с толку то, что вы используете t для замены my_table, а также в качестве явного псевдонима во время первого кода. Также в первом коде вы делаете max для next_id, что означает, что вы теряете текущий идентификатор, и передаете ему соединение m и n, данные из m недоступны в остальной части запроса. - person Simeon Pilgrim; 22.12.2019
comment
Вау, мне очень нравится использование FETCH / LIMIT, мне никогда не приходило в голову поместить это в подзапрос / CTE. - person Simeon Pilgrim; 22.12.2019

Я не уверен, как это вплетено в остальную часть вашего запроса, поэтому я использовал CTE

WITH max_next AS (
    SELECT r.id as max_id
        ,r.next_id
    FROM (
        SELECT m.id
            ,m.next_id
            ,ROW_NUMBER() OVER (ORDER BY m.id DESC) AS rn
        FROM (
            SELECT n.* -- to provide data to satisfy CONDITIONS
                ,LEAD(n.id) OVER(ORDER BY n.id) as next_id
            FROM my_table AS n
        ) AS m
        WHERE CONDITIONS
    ) AS r
    WHERE r.rn = 1
) 

Я бы также сократил n. * До столбцов, необходимых для УСЛОВИЙ, до a, не быть неявным, поскольку * замедляет время компиляции (или имеет историческое значение), поскольку все метаданные должны быть прочитаны, чтобы понять, какие столбцы находятся в ЛЮБОМ, и хотя компиляция также может обрезать неиспользуемые столбцы, это быстрее, если вы просто попросите то, что вы хотите (в лучшем случае просто экономия времени на компиляцию, в худшем случае он прочитает все данные, когда вам нужно только x количество прочитанных столбцов)

И заимствуя решение Гордона, ROW_NUMBER часть могла бы быть проще.

WITH max_next AS (
    SELECT m.id
        ,m.next_id
        --, plus what ever other things you want from m
    FROM (
        SELECT n.* -- to satisfy CONDITIONS needs
            ,LEAD(n.id) OVER(ORDER BY n.id) as next_id
        FROM my_table AS n
    ) AS m
    WHERE CONDITIONS
    ORDER BY m.id DESC LIMIT 1
)  

Итак, например, для @PIG,

WITH my_table AS (
    SELECT column1 AS id
        ,column2 AS con1
        ,column3 AS other
    FROM VALUES (1,'a',123),(2,'b',234),(3,'a',345),(5,'b',456),(7,'a',567),(10,'c',678)
)
SELECT m.id
    ,m.next_id
    ,m.other
FROM (
    SELECT n.* -- to satisfy CONDITIONS needs
        ,LEAD(n.id) OVER(ORDER BY n.id) as next_id
    FROM my_table AS n
) AS m
WHERE m.con1 = 'b'
ORDER BY m.id DESC LIMIT 1;

дает 5, 7, 456, который является последним 'b' и новой строкой, и дополнительное значение в my_table для развлекательных целей (и запускается в Snowflake to, что означает, что я также исправил предыдущий SQL).

person Simeon Pilgrim    schedule 22.12.2019
comment
Привет, @Simeon Pilgrim. Не могли бы вы предоставить образцы данных, по которым я могу выполнить ваш запрос. - person PIG; 23.12.2019
comment
@PIG Я не создавал ни одного, поскольку SQL казался достаточно простым, вас беспокоит, что мое решение не работает? Или вы хотите, чтобы я объяснил, почему я думаю, что это сработает? - person Simeon Pilgrim; 23.12.2019
comment
Я просто хотел попрактиковаться в вашем коде в учебных целях. - person PIG; 23.12.2019

Это должно сработать, это довольно просто (легко), и хорошо, что вы знаете, что записи не могут храниться в упорядоченном / последовательном порядке.

SELECT *
FROM   my_table
WHERE  id = (
  SELECT min(id)
  FROM   my_table
  WHERE  id > (
    SELECT max(id)
    FROM   my_table
    WHERE  CONDITION));
person Rich Murnane    schedule 20.12.2019