优化 SQL 脚本:从另一个 table 获取范围值

Optimize SQL Script: getting range value from another table

我认为我的脚本应该是 运行ning,但可能不是 'efficient',主要问题是我想 运行 花费的时间太长,因此当我 运行 它在工作,整个会话在它完成之前被中止。

我基本上有2张桌子 Table A - 包含一个人所做的每笔交易

Person's_ID Transaction TransactionDate
---------------------------------------
123             A         01/01/2017
345             B         04/06/2015
678             C         13/07/2015
123             F         28/10/2016

Table B - 包含人员 ID 和毕业日期

我想做的是检查一个人是否活跃。 活跃 = 如果此人在毕业日期前 1 个月至少完成了 1 笔交易

运行时间太长了,因为想象一下,如果我有数百万人,每个人进行多次交易,这些交易逐行记录在Table A

SELECT
PERSON_ID
FROM
   (SELECT PERSON_ID, TRANSACTIONDATE FROM TABLE_A) A
LEFT JOIN
   (SELECT CIN, GRAD_DATE FROM TABLE_B) B
ON A.PERSON_ID = B.PERSON_ID
AND TRANSACTIONDATE <= GRAD_DATE
WHERE TRANSACTIONDATE BETWEEN GRAD_DATE - INTERVAL '30' DAY AND GRAD_DATE;

*Table A 和 B 是连接表的产物,因此它们被子查询。

如果您只想要活跃客户,我会尝试 exists:

SELECT PERSON_ID
FROM TABLE_A A
WHERE EXISTS (SELECT 1
              FROM TABLE_B B
              WHERE A.PERSON_ID = B.PERSON_ID AND
                    A.TRANSACTIONDATE BETWEEN B.GRAD_DATE - INTERVAL '30' DAY AND GRAD_DATE
             );

不过,性能可能与您的查询相似。如果表真的是表,我建议使用索引。实际上,您可能需要了解视图(以便创建更好的索引)或者使用临时表。

非等值连接可能效率很低(无论它被编码为连接还是不存在),但逻辑可以重写为:

SELECT 
   PERSON_ID
FROM
 ( -- combine both Selects
    SELECT 0 AS flag -- indicating source table
       PERSON_ID, TRANSACTIONDATE AS dt
    FROM TABLE_A
    UNION ALL
    SELECT 1 AS flag,
       PERSON_ID, GRAD_DATE
    FROM TABLE_B
 ) A
QUALIFY 
   flag = 1 -- only return a row from table B
AND Min(dt) -- if the previous row (from table A) is within 30 days
    Over (PARTITION BY PERSON_ID
          ORDER BY dt, flag
          ROWS BETWEEN 1 Preceding AND 1 Preceding) >= dt - 30

这假设每个人只有 table 一行,否则 MIN 必须更改为:

AND MAX(CASE WHEN flag = 1 THEN dt END) -- if the previous row (from table A) is within 30 days
    Over (PARTITION BY PERSON_ID
          ORDER BY dt, flag
          ROWS UNBOUNDED Preceding) >= dt - 30