使用“not in”子句重写相关子查询

时间:2013-12-17 15:29:05

标签: sql oracle correlated-subquery

出于显而易见的性能原因,我想重写现有的Oracle SQL查询,其中包含涉及“not in”子句的相关子查询。这可以通过外连接或其他一些技术来实现吗?

以下是代码:

SELECT TRIM(et.event_id), TRIM(et.cancel_evt_id)
FROM external_transactions et
JOIN transaction_type tt
    ON et.transaction_type_id = tt.transaction_type_id
WHERE et.acct = 'ABCDEF' 
AND tt.transaction_type_class != 'XYZXYZ'
AND 
(
    TRIM(et.event_id) NOT IN
        (
        SELECT TRIM(t1.transaction_evt_id)
        FROM transactions t1
        WHERE t1.acct = et.acct
        AND t1.asset_id = et.asset_id
        AND t1.cancel_flag = 'N' 
        )
    OR TRIM(et.cancel_evt_id) NOT IN
        (
        SELECT TRIM(t2.cancel_evt_id)
        FROM transactions t2
        WHERE t2.acct = et.acct
        AND t2.asset_id = et.asset_id
        AND t2.cancel_flag = 'Y'
        )
)
;

2 个答案:

答案 0 :(得分:0)

使用NOT EXISTS

SELECT TRIM(et.event_id), TRIM(et.cancel_evt_id)
FROM external_transactions et
JOIN transaction_type tt
    ON et.transaction_type_id = tt.transaction_type_id
WHERE et.acct = 'ABCDEF' 
AND tt.transaction_type_class != 'XYZXYZ'
AND NOT EXISTS
        (
        SELECT 1
        FROM transactions t1
        WHERE t1.acct = et.acct
        AND t1.asset_id = et.asset_id
        AND ( (   t1.cancel_flag = 'N'
              AND TRIM(et.event_id) = TRIM(t1.transaction_evt_id) )
            OR
              (   t1.cancel_flag = 'Y'
              AND TRIM(et.cancel_evt_id) = TRIM(t1.cancel_evt_id) )
            )
        );

答案 1 :(得分:0)

除了评论,这是假设您的“ID”列是基于整数而不是字符串,不要尝试转换它们。

另外,为了帮助优化查询,我会确保你有索引

External_Transactions    ( acct, event_id, cancel_evt_id )
Transaction_Type   ( transaction_type_id, transaction_type_class )
Transactions ( transaction_evt_id, acct, asset_id, cancel_flag )
Transactions ( cancel_evt_id, acct, asset_id, cancel_flag )


SELECT 
      et.event_id, 
      et.cancel_evt_id
   FROM 
      external_transactions et
         JOIN transaction_type tt
            ON et.transaction_type_id = tt.transaction_type_id
           AND tt.transaction_type_class != 'XYZXYZ'
         LEFT OUTER JOIN transactions t1
            ON  et.event_id = t1.transaction_evt_id
            AND et.acct = t1.acct
            AND et.asset_id = t1.asset_id
            AND t1.cancel_flag = 'N'
         LEFT OUTER JOIN transactions t2
            ON  et.cancel_evt_id = t2.cancel_evt_id
            AND et.acct = t2.acct
            AND et.asset_id = t2.asset_id
            AND t2.cancel_flag = 'Y'
   WHERE 
          et.acct = 'ABCDEF' 
      AND (    t1.transaction_evt_id IS NULL
            OR t2.cancel_evt_id IS NULL )

如果交易表上有索引

,您甚至可能会受益匪浅
Transactions ( acct, asset_id, cancel_flag, transaction_evt_id, cancel_evt_id )

并且左连接就像

SELECT 
      et.event_id, 
      et.cancel_evt_id
   FROM 
      external_transactions et
         JOIN transaction_type tt
            ON et.transaction_type_id = tt.transaction_type_id
           AND tt.transaction_type_class != 'XYZXYZ'
         LEFT OUTER JOIN transactions t1
            ON  et.acct = t1.acct
            AND et.asset_id = t1.asset_id
            AND ( 
                  (   t1.cancel_flag = 'N'
                  AND et.event_id = t1.transaction_evt_id )
                OR
                  (   t1.cancel_flag = 'Y'
                  AND et.cancel_event_id = t1.cancel_evt_id )
                )
   WHERE 
          et.acct = 'ABCDEF' 
      AND t1.transaction_evt_id IS NULL

在这两种情况下,索引都是COVERING索引,因此它不必返回原始数据页面来确认记录的其他元素