SQL查询中使用NOT EXISTS过滤CUSTDEF_ID时的结果异常问题
我来帮你梳理下这个问题,你现在的需求很明确:要保留两类数据——一类是没有关联custom_data的订单行(就是前两行custdef_id为NULL的记录),另一类是关联了custom_data且custdef_id为13或15的行(也就是最后一行custdef_id=15的记录),同时要排除custdef_id为20、21的行。
你第二个查询里的NOT EXISTS逻辑写反了,导致本该保留的行被过滤掉了:原语句的NOT EXISTS(SELECT * FROM CUSTOM_DATA C WHERE T.DETAIL_LINE_ID = C.SRC_TABLE_KEY and C.custdef_id NOT in ('20','21') )意思是仅当某个订单行对应的所有custom_data记录的custdef_id都是20或21时,才保留这个订单行。但T121374有custdef_id=15的记录,所以这个条件不成立,整行就被排除了,这显然和你的需求相悖。
下面给你两种简单可行的解决方案:
方案一:在LEFT JOIN时直接过滤关联表
我们可以在LEFT JOIN的关联条件里就限定只拉取custdef_id为13、15的custom_data记录,这样没有关联的订单行会保留NULL,符合条件的关联行会正常显示,20、21的记录根本不会被关联进来:
SELECT BILL_NUMBER, deliver_by_end, actual_delivery, c.custdef_id, (case when c.custdef_id = '13' then c.data end) "Late Flag", (case when c.custdef_id = '15' then c.data end) "Planned Late Flag" FROM TLORDER_all T LEFT join custom_data c on t.detail_line_id = c.src_table_key AND c.custdef_id IN ('13','15') -- 在这里过滤关联表的条件 WHERE bill_number in ('T119633','T119634','T121374') AND DATE(T.DELIVER_BY) between :STARTDATE and :ENDDATE and companY_id = '1' AND T.ACTUAL_DELIVERY IS NOT NULL AND ((T.ACTUAL_DELIVERY > (T.DELIVER_BY_END + :MINUTESLATE MINUTES) AND TIME(T.DELIVER_BY_END) <> '00:00:00') OR ((TIME(T.DELIVER_BY_END)) = '00:00:00' AND T.ACTUAL_DELIVERY >= T.DELIVER_BY_END + 1 DAY)) order by customer, bill_number
方案二:在WHERE子句中过滤结果行
如果你不想修改JOIN条件,也可以在WHERE里直接添加过滤规则,保留custdef_id为NULL或者13、15的行:
SELECT BILL_NUMBER, deliver_by_end, actual_delivery, c.custdef_id, (case when c.custdef_id = '13' then c.data end) "Late Flag", (case when c.custdef_id = '15' then c.data end) "Planned Late Flag" FROM TLORDER_all T LEFT join custom_data c on t.detail_line_id = c.src_table_key WHERE bill_number in ('T119633','T119634','T121374') AND DATE(T.DELIVER_BY) between :STARTDATE and :ENDDATE and companY_id = '1' AND T.ACTUAL_DELIVERY IS NOT NULL AND ((T.ACTUAL_DELIVERY > (T.DELIVER_BY_END + :MINUTESLATE MINUTES) AND TIME(T.DELIVER_BY_END) <> '00:00:00') OR ((TIME(T.DELIVER_BY_END)) = '00:00:00' AND T.ACTUAL_DELIVERY >= T.DELIVER_BY_END + 1 DAY)) -- 添加这一行过滤不需要的custdef_id AND (c.custdef_id IS NULL OR c.custdef_id IN ('13','15')) order by customer, bill_number
这两种方案都能得到你想要的结果:保留前两行无关联的订单,以及最后一行custdef_id=15的记录,同时排除20、21的行。
备注:内容来源于stack exchange,提问作者Allen

