使用 select 查询的结果作为另一个 select 查询中的 where 子句的参数?

问题描述 投票:0回答:1

这就是它目前的工作方式,首先选择查询返回参数列表。

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 ...

但是第一个查询结果的结果不能在第二个查询的最深层 select 中使用

postgresql postgresql-16
1个回答
0
投票

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
         OFFSET 0
         ) 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
         OFFSET 0
         ) 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;

当然可以进一步简化。但这超出了这个问题的范围。

© www.soinside.com 2019 - 2024. All rights reserved.