在下一个查询的 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 中使用。

sql postgresql lateral-join 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
         ) 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 中混合大小写标识符。参见:

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