Использовать результаты одного запроса в предложении WHERE следующего запроса

Вот как это работает в настоящее время: первый запрос выбора возвращает список параметров.

SELECT character_id, foe_id, location_id, date_time, damage, points 
FROM events 
ORDER BY date_time DESC 
LIMIT 100

Теперь следующее повторяется 100 раз для завершения данных, например, возвращается первый:

  character_id = 12695
, location_id = 818
, foe_id = 33997
, date_time = '2024-05-02 23:00:00'

Следующий запрос основан на этих результатах:

SELECT *, A1+B1-C1-D1-E1-F1+G1+H1 AS A2 
FROM 
    (SELECT * 
     FROM 
         (SELECT id_, cnt_7, date_diff_7 , NTH_VALUE (A0,1) OVER() AS A1, NTH_VALUE (A0,2) OVER() AS B1, NTH_VALUE (B0,1) OVER() AS C1, NTH_VALUE (B0,2) OVER() AS D1 
          FROM 
              (SELECT damage AS A0, points AS B0, RootQuery_7.id as id_, count(*) over() as cnt_7,  max(date_diff) over() as date_diff_7 
               FROM 
                   (SELECT *, extract(day from date_time - lag(date_time) over (ORDER BY date_time)) as date_diff 
                    FROM events 
                    WHERE character_id = 12695 
                      AND status = 1 
                      AND location_id = 818 
                      AND date_time < '2024-05-02 23:00:00' 
                    ORDER BY date_time DESC 
                    LIMIT 10 OFFSET 0) AS RootQuery_7) 
            AS BaseQuery7 LIMIT 1) wnd_1 
        JOIN (SELECT id_, cnt_8, date_diff_8 , NTH_VALUE (D0,2) OVER() AS H1, NTH_VALUE (C0,1) OVER() AS E1, NTH_VALUE (C0,2) OVER() AS F1, NTH_VALUE (D0,1) OVER() AS G1 FROM 
            (SELECT damage AS C0, points AS D0, RootQuery_8.id as id_, count(*) over() as cnt_8,  max(date_diff) over() as date_diff_8 FROM 
                (SELECT *, extract(day from date_time - lag(date_time) over (ORDER BY date_time)) as date_diff FROM events WHERE foe_id = 33997 AND status = 1 AND location_id = 818 AND date_time < '2024-05-02 23:00:00' ORDER BY date_time DESC LIMIT 15 OFFSET 0)
                    AS RootQuery_8)
            AS BaseQuery8 LIMIT 1) wnd_2
    ON wnd_1.id_ <> 0 WHERE cnt_7 >= 10 AND date_diff_7 <= 150 AND cnt_8 >= 10 AND date_diff_8 <= 150) AS layer_1

Это работает, но слишком неэффективно и медленно, не обращайте внимания на правдоподобие полученных данных, поскольку это пример.

Я пытаюсь получить этот список результатов из одного запроса следующим образом:

(SELECT character_id, foe_id, location_id, date_time, damage, points FROM events ORDER BY date_time DESC LIMIT 100) ref_
JOIN
SELECT *, A1+B1-C1-D1-E1-F1+G1+H1 AS A2 FROM 
    (SELECT * FROM 
        (SELECT id_, cnt_7, date_diff_7 , NTH_VALUE (A0,1) OVER() AS A1, NTH_VALUE (A0,2) OVER() AS B1, NTH_VALUE (B0,1) OVER() AS C1, NTH_VALUE (B0,2) OVER() AS D1 FROM 
            (SELECT damage AS A0, points AS B0, RootQuery_7.id as id_, count(*) over() as cnt_7,  max(date_diff) over() as date_diff_7 FROM 
                (SELECT *, extract(day from date_time - lag(date_time) over (ORDER BY date_time)) as date_diff FROM events WHERE character_id = ref_.character_id  AND status = 1 AND location_id = ref_.location_id AND date_time < location_id = ref_.date_time ORDER BY date_time DESC LIMIT 10 OFFSET 0)te_time
                    AS RootQuery_7) 
            AS BaseQuery7 LIMIT 1) wnd_1 
        JOIN (SELECT id_, cnt_8, date_diff_8 , NTH_VALUE (D0,2) OVER() AS H1, NTH_VALUE (C0,1) OVER() AS E1, NTH_VALUE (C0,2) OVER() AS F1, NTH_VALUE (D0,1) OVER() AS G1 FROM 
            (SELECT damage AS C0, points AS D0, RootQuery_8.id as id_, count(*) over() as cnt_8,  max(date_diff) over() as date_diff_8 FROM 
                (SELECT *, extract(day from date_time - lag(date_time) over (ORDER BY date_time)) as date_diff FROM events WHERE foe_id = ref_.foe_id  AND status = 1 AND location_id = ref_.location_id AND date_time < location_id = ref_.date_time ORDER BY date_time DESC LIMIT 15 OFFSET 0)
                    AS RootQuery_8)
            AS BaseQuery8 LIMIT 1) wnd_2
    ON wnd_1.id_ <> 0 WHERE cnt_7 >= 10 AND date_diff_7 <= 150 AND cnt_8 >= 10 AND date_diff_8 <= 150) AS layer_1
ON ...

Но результат результатов первого запроса не может быть использован на самом глубоком уровне выбора во втором запросе.

.сделайте что-нибудь МИЛОЕ, чтобы вы могли получить доступ к результатам запросов

nbk 04.05.2024 01:53

Если запрос выполняется медленно, начните получать план запроса, используя explain(analyze, verbose, buffers, settings). Тогда вы увидите, почему это медленно и что нужно улучшить.

Frank Heikens 04.05.2024 01:59

@FrankHeikens нет, нет, проблема не в запросе, проблема в том, что мне приходится запускать его 100 раз, чтобы получить нужные мне данные

Mario Orozco 04.05.2024 02:34

@nbk, я не пытаюсь выполнить запрос на основе результата другого запроса, а использовать результаты первого запроса в качестве параметра для предложения WHERE во втором, кстати, спасибо за ответ!

Mario Orozco 04.05.2024 02:40
ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
1
4
62
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

TLDR: используйте соединение LATERAL.

LATERAL соединения позволяют подзапросам справа ссылаться на столбцы в FROM элементах слева. Видеть:

Ваш запрос может выглядеть примерно так:

SELECT *, A1+B1-C1-D1-E1-F1+G1+H1 AS A2
FROM  (
   SELECT character_id, foe_id, location_id, date_time, damage, points FROM events ORDER BY date_time DESC LIMIT 100
   ) prime
JOIN LATERAL (  -- !
   SELECT id_, cnt_7, date_diff_7
        , nth_value(A0,1) OVER () AS A1, nth_value(A0,2) OVER () AS B1, nth_value(B0,1) OVER () AS C1, nth_value(B0,2) OVER () AS D1
   FROM  (
      SELECT damage AS A0, points AS B0, RootQuery_7.id AS id_, count(*) OVER () AS cnt_7,  max(date_diff) OVER () AS date_diff_7
      FROM  (
         SELECT *, extract(day FROM e.date_time - lag(e.date_time) OVER (ORDER BY e.date_time)) AS date_diff
         FROM   events e
         WHERE  e.status = 1
         AND    e.character_id = prime.character_id  -- LATERAL reference
         AND    e.location_id  = prime.location_id   -- LATERAL reference
         AND    e.date_time    < prime.date_time     -- LATERAL reference
         ORDER  BY e.date_time DESC
         LIMIT  10
         ) AS RootQuery_7
      ) AS BaseQuery7
      LIMIT 1
   ) wnd_1 ON wnd_1.id_ <> 0
CROSS JOIN LATERAL (  -- !
   SELECT id_, cnt_8, date_diff_8 , nth_value(D0,2) OVER () AS H1, nth_value(C0,1) OVER () AS E1, nth_value(C0,2) OVER () AS F1, nth_value(D0,1) OVER () AS G1
   FROM  (
      SELECT damage AS C0, points AS D0, RootQuery_8.id AS id_, count(*) OVER () AS cnt_8,  max(date_diff) OVER () AS date_diff_8
      FROM  (
         SELECT *, extract(day from date_time - lag(date_time) OVER (ORDER BY date_time)) AS date_diff
         FROM   events
         WHERE  status = 1
         AND    foe_id      = prime.foe_id       -- LATERAL reference
         AND    location_id = prime.location_id  -- LATERAL reference
         AND    date_time   < prime.date_time    -- LATERAL reference
         ORDER  BY date_time DESC
         LIMIT  15
         ) RootQuery_8
      ) BaseQuery8
   LIMIT 1
   ) wnd_2
WHERE  wnd_1.cnt_7 >= 10
AND    wnd_1.date_diff_7 <= 150
AND    wnd_2.cnt_8 >= 10
AND    wnd_2.date_diff_8 <= 150;

Конечно, можно еще упростить. Но это выходит за рамки данного вопроса.

Два экземпляра LIMIT 1 без ORDER BY приводят к произвольным результатам. Вероятно, следует исправить (или удалить).

В сторону:
По возможности избегайте идентификаторов в смешанном регистре в Postgres. Видеть:

Большое спасибо, ваш ответ - чистое золото, именно то, что мне нужно! причина этого «LIMIT 1» в запросе Windows заключается в том, что он возвращает 10 строк с одинаковым выводом.

Mario Orozco 04.05.2024 04:19

Другие вопросы по теме