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

时间:2017-06-30 01:57:01

标签: sql teradata

我认为我的剧本应该正在运行,但可能并不是那么有效'主要的问题是我猜它运行时间太长,因此当我在工作中运行时,整个会话在完成之前就会中止。

我基本上有2张桌子 表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

表B - 包含人的ID和GraduationDate

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

运行时间太长,因为想象一下,如果我有数百万人,每个人进行多次交易,这些交易在表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;

*表A和B是连接表的产品,因此它们是次要的。

2 个答案:

答案 0 :(得分:0)

如果您只想要活跃客户,我会尝试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
             );

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

答案 1 :(得分:0)

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

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

这假定每人只有一个表A行,否则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