创建条件 SQL 查询的最佳方法? CASE、DECODE 还是 IF/THEN?

问题描述 投票:0回答:2

我试图使这个查询的一部分成为有条件的,但我真的很难做到这一点。下面我输入了一些代表我的查询的伪代码。

主要查询

SELECT A.T_NBR
,A.I_NBR
,A.DATE
,A.MX_CD
,A.MY_CD
,A.S_CD
,B.O_NBR
FROM A,B,C,D,E,F,H,I,TMP_J
WHERE A.MY_CD IN ('FOO','BAR')
AND A.T_NBR NOT IN (
   SELECT A.T_NBR
   FROM A,K
   WHERE A.MY_CD = 'BAR'
   AND P_DATE < ADD_MONTHS(SYSDATE, -36)
   AND A.S_CD NOT IN ('AAA','BBB')
   AND K.K_CD NOT IN ('DDD','EEE')
   --JOIN
   AND A.I_NBR = K.I_NBR(+)
)
AND U_CD = 'FFFF'
--DATE LESS THAN 3 YEARS
AND TO_DATE(H.DATE,'YYYY-MM-DD') < ADD_MONTHS(SYSDATE, -36)
--NUM GREATER THAN 23 
AND TO_CHAR(SYSDATE,'SYYYY')-TO_CHAR(I.NUM,'SYYYY') > 23
AND A.S_CD NOT IN ('AAA','BBB')
AND B.DATE = (
   SELECT MAX(DATE)
   FROM B
)
AND B.O_NBR < 200
AND F.MG_CD <> '000'
AND A.T_NBR NOT IN (12345,54321,98765)
AND ((E.T IS NULL) OR (RTRIM(E.T) LIKE '%###%'))
AND TMP_J.I_NBR IS NULL
--JOINS
AND A.T_BR = B.T_NBR(+)
AND ((B.I_NBR = F.I_NBR) AND (B.DATE = F.DATE))
AND A.S_NBR = D.S_NBR(+)
AND A.D_NBR = C.D_NBR(+)
AND ((D.S_NBR = G.S_NBR(+)) AND (UPPER(G.A_CD(+)) = 'XXX'))
AND G.A_NBR = E.A_NBR(+)
AND H.I_NBR = A.I_NBR
AND A.S_NBR = I.S_NBR(+)
AND A.T_NBR = TMP_J.T_NBR(+);

本质上,这就是我想要做的条件(用简单的英语和伪代码写出来):

如果

A.MY_CD = 'BAR'

然后

A.T_NBR NOT IN (
   SELECT A.T_NBR
   FROM A,K
   WHERE A.MY_CD = 'BAR'
   AND P_DATE < ADD_MONTHS(SYSDATE, -36)
   AND A.S_CD NOT IN ('AAA','BBB')
   AND K.K_CD NOT IN ('DDD','EEE')
   --JOIN
   AND A.I_NBR = K.I_NBR(+)
)

否则如果

A.MY_CD = 'FOO'

然后

WHERE U_CD = 'FFFF'
--DATE LESS THAN 3 YEARS
AND TO_DATE(H.DATE,'YYYY-MM-DD') < ADD_MONTHS(SYSDATE, -36)
--NUM GREATER THAN 23 
AND TO_CHAR(SYSDATE,'SYYYY')-TO_CHAR(I.NUM,'SYYYY') > 23

然后我只想其余的 where 子句在 Condition 之外进行操作。

除了不知道哪种方法最有效(CASE/WHEN、DECODE、IF/THEN)之外,我真正遇到困难的部分是尝试在这些条件子句中实现 SELECT 语句。我尝试在查询的 SELECT 和 WHERE 部分中实现 CASE WHEN,同时尝试将 SELECT 语句放在 CASE 语句的 WHEN 部分中。我也以同样的方式尝试过解码。此外,我尝试实现 IF/THEN,但似乎无法将其与我的主查询联系起来。

对于 PL/SQL,我当然不是专业人士,所以这可能只是我的知识失误。使该查询的一部分成为条件的最佳方法是什么?

非常感谢您的回复和帮助!

sql oracle plsql case decode
2个回答
0
投票

您似乎只想将条件与 AND/OR 逻辑结合起来;无需对您的方法进行任何其他更改:

...
FROM A,B,C,D,E,F,H,I,TMP_J
WHERE
(
   (
      A.MY_CD = 'BAR'
      AND A.T_NBR NOT IN (
         SELECT A.T_NBR
         FROM A,K
         WHERE A.MY_CD = 'BAR'
         AND P_DATE < ADD_MONTHS(SYSDATE, -36)
         AND A.S_CD NOT IN ('AAA','BBB')
         AND K.K_CD NOT IN ('DDD','EEE')
         --JOIN
         AND A.I_NBR = K.I_NBR(+)
      )
   )
   OR
   (
      A.MY_CD = 'FOO'
      AND U_CD = 'FFFF'
      --DATE LESS THAN 3 YEARS
      AND TO_DATE(H.DATE,'YYYY-MM-DD') < ADD_MONTHS(SYSDATE, -36)
      --NUM GREATER THAN 23 
      AND TO_CHAR(SYSDATE,'SYYYY')-TO_CHAR(I.NUM,'SYYYY') > 23
   )
)
AND A.S_CD NOT IN ('AAA','BBB')
AND B.DATE = (
   SELECT MAX(DATE)
   FROM B
)
AND B.O_NBR < 200
AND F.MG_CD <> '000'
AND A.T_NBR NOT IN (12345,54321,98765)
AND ((E.T IS NULL) OR (RTRIM(E.T) LIKE '%###%'))
AND TMP_J.I_NBR IS NULL
--JOINS
...

从逻辑上讲,这似乎就是您所要求的。但您需要查看执行计划和性能等。还有各种其他问题需要考虑,包括切换到使用显式连接,

not in
vs
not exists
(如评论中所述),不将日期存储为字符串,也许使用(更多,现代)连接而不是子查询,也许使用
extract()
获取您的年份数字而不是
to_char()
并隐式转换为数字(如果该子句有意义),等等。


0
投票

这是我的想法:

IF A = X
THEN 
  IF B = Y
    CASE 1
  ELSE
    CASE 2
ELSE 
  IF C = Z
    CASE 3

可以重写为

 IF (A = X) AND (B = Y)
   CASE 1

 IF (A = X) AND (B != Y)
   CASE 2

 IF (A != X) AND (C = Z)
   CASE 3

可以将其翻译成如下 SQL WHERE 语句:

 WHERE 
     -- Case 1
     ((A = X) AND (B = Y))  -- you can put more clauses here with AND statements
   OR
     -- Case 2
     ((A = X) AND (B != Y)) -- you can put more clauses here with AND statements
   OR
     -- Case 3
     ((A != X) AND (C = Z)) -- you can put more clauses here with AND statements

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