Oracle SQL - 多个条件基于相同表中的彼此条件

时间:2016-06-13 12:02:15

标签: sql oracle

我有一个表ledrow,其中有4列。

我想只选择他们拥有的行(每个vnumcomp)两个逻辑集中的行。

英文解释

例如,在下面的所有数据中,解释预期输出中的行如下:

对于comp 99,我们得到了结果,因为所有vacc个数字都属于任何一组逻辑:

vaccBETWEEN '1544' AND '1567'vaccBETWEEN '3000' AND '3999'

但是,例如comp不输出77行,因为即使:

comp vtype  vnum    vacc
77   F      1369    3400
77   F      1369    3402

根据逻辑的第二部分,其余行不属于任何行:

comp vtype  vnum    vacc
77   F      1369    1510
77   F      1369    2620
77   F      1369    2620
77   F      1369    2620
77   F      1369    1650

这是因为要成为输出的一部分,我希望每个comp的所有行必须落在每个comp的逻辑的任一部分。

我尝试过以下代码,但无法获得预期的输出。

当前代码:

SELECT * FROM (
SELECT comp, vtype, vnum, vacc
FROM ledrow
WHERE 
((comp = '55' AND vacc BETWEEN '1544' AND '1567') AND (comp = '55' AND (vacc = '3019' OR vacc = '5222')))
OR
((comp = '66' AND vacc BETWEEN '1544' AND '1567') AND (comp = '66' AND (vacc  = '3013' OR (vacc BETWEEN '6910' AND '6973'))))
OR
((comp NOT IN ('55', '66') AND vacc BETWEEN '1544' AND '1567') AND (comp NOT IN ('55', '66') AND (vacc BETWEEN '3000' AND '3999')))) outputled
WHERE outputled.vtype = 'F'

预期产出:

comp vtype  vnum    vacc
99   F      1369    1564
99   F      1369    2610
99   F      1369    2610
99   F      1369    3601
99   F      1369    3600

完整表格(SELECT * FROM ledrow):

ledrow

comp vtype  vnum    vacc
77   F      1369    1510
77   F      1369    2620
77   F      1369    2620
77   F      1369    2620
77   F      1369    3400
77   F      1369    3402
77   F      1369    1650
99   F      1369    1564
99   F      1369    2610
99   F      1369    2610
99   F      1369    3601
99   F      1369    3600
99   I      1369    2450
99   I      1369    2440
99   I      1369    2640
99   J      1369    5430
99   J      1369    2450
99   J      1369    5430
99   J      1369    2455
99   J      1369    5410
99   J      1369    2455
99   J      1369    5410
22   F      1369    2620
22   F      1369    3500
22   F      1369    2495
22   F      1369    1510
22   F      1369    2620
22   F      1369    2620
22   F      1369    2620
22   F      1369    2620
22   F      1369    2620
22   F      1369    2620
22   F      1369    2620
22   F      1369    2620
22   F      1369    2620
22   F      1369    3500
22   F      1369    3500
22   F      1369    3500
22   F      1369    3500
22   F      1369    3500
22   F      1369    3500
22   F      1369    3500
22   F      1369    3500
22   F      1369    3500
22   F      1369    3500
22   F      1369    3500
22   F      1369    2495
22   F      1369    3500
22   F      1369    2495
22   F      1369    3500
22   F      1369    2495
22   F      1369    3500
22   F      1369    2495
22   F      1369    3500
22   F      1369    2495
22   F      1369    3500
22   F      1369    2495
22   F      1369    3500
22   F      1369    2495
22   F      1369    3500
22   F      1369    2495
22   F      1369    3500
22   F      1369    2495
22   I      1369    2450
22   I      1369    2440
22   I      1369    2640
22   J      1369    5520
22   J      1369    5520
22   J      1369    2455
22   J      1369    2450

修改

因此,对于每个vnumcomp,它需要满足WHERE子句中的两个条件。

因此comp 99必须满足这两个条件:

((comp NOT IN ('55', '66') AND vacc BETWEEN '1544' AND '1567') AND (comp NOT IN ('55', '66') AND (vacc BETWEEN '3000' AND '3999'))))

2 个答案:

答案 0 :(得分:3)

如果我理解你想要做什么,那么这应该有效:

    WHERE comp = '55' AND (vacc between '1544' and '1567' or vacc in('3019','5222')) OR
          (comp = '66' AND (vacc between '1544' and '1567' or vacc between '6910' AND '6973' or vacc = '3013')) OR
          (comp not IN('55','66') and (vacc BETWEEN '1544' AND '1567' or vacc BETWEEN '3000' AND '3999'))

您指定了每个第一个条件两次,这是不必要的,因为它们对于下两个条件都是正确的。

(comp not IN('55','66') AND Cond1) AND/OR (comp not IN('55','66') AND Cond2)

等于:

comp not IN('55','66') AND (Cond1 AND/OR Cond2)

编辑你可以尝试这样的事情:

SELECT tt.* FROM (
    SELECT t.comp FROM (
        SELECT comp,
               CASE WHEN comp = '55' AND vacc BETWEEN '1544' AND '1567' THEN 1
                    WHEN comp = '55' AND vacc in('3019','5222') THEN 2
                    WHEN comp = '66' AND vacc BETWEEN '1544' AND '1567' THEN 3
                    WHEN comp = '66' AND (vacc  = '3013' OR (vacc BETWEEN '6910' AND '6973')) THEN 4
                    WHEN comp NOT IN ('55', '66') AND vacc BETWEEN '1544' AND '1567' THEN 5
                    WHEN comp NOT IN ('55', '66') AND (vacc BETWEEN '3000' AND '3999') THEN 6
                    ELSE 7
                END as ind_col
        FROM ledrow
        WHERE vtype = 'F') t
    GROUP BY t.comp 
    HAVING (MAX(t.ind_col) = 2 and min(t.ind_col) = 1) OR
           (MAX(t.ind_col) = 4 and min(t.ind_col) = 3) OR
           (MAX(t.ind_col) = 6 and min(t.ind_col) = 5)) s
INNER JOIN ledrow tt
 ON(s.comp = tt.comp)
WHERE tt.vtype = 'F'

这基本上会给出每一行的指示,第一个条件是1,2,对应于满足条件的部分,第二个是3,4,第三个是5,6。然后,检查每个组只有1 + 2或3 + 4或5 + 6与HAVING子句MAX()MIN(),这将确保此comp满足两个条件。

此解决方案仅适用于满足这两个条件的行,而不仅仅适用于其中一个行。如果只有其中一个就足够了,那就将having子句更改为:

    HAVING (MAX(t.ind_col) = 2 and min(t.ind_col) = 1) OR
           (MAX(t.ind_col) = 4 and min(t.ind_col) = 3) OR
           (MAX(t.ind_col) = 6 and min(t.ind_col) = 5) OR
           (MAX(t.ind_col) = min(t.ind_col) and min(t.ind_col) IN(1,2,3,4,5,6)

答案 1 :(得分:2)

可能我已经理解了你想要的东西:)

我们为每个comp(group by comp)创建每个特殊条件,就像一个字节(1,2,4,8)中的位,然后添加它们。比我们只选择我们想要的组合。 (1 + 2 = 3,1 + 4 = 5,1 + 8 = 9)

SELECT *
  FROM ledrow
 WHERE vtype = 'F'
   AND comp IN 
      (SELECT comp
         FROM (  SELECT comp,
                        MAX (CASE WHEN (vacc BETWEEN '1544' AND '1567') THEN 1 ELSE 0 END)
                        + MAX (CASE WHEN (comp = '55' AND vacc IN ('3019', '5222')) THEN 2 ELSE 0 END)
                        + MAX (CASE WHEN (comp = '66' AND (vacc = '3013' OR vacc BETWEEN '6910' AND '6973')) THEN 4 ELSE 0 END)
                        + MAX (CASE WHEN (comp NOT IN ('55', '66') AND vacc BETWEEN '3000' AND '3999') THEN 8 ELSE 0 END)
                           x
                   FROM ledrow
                  WHERE vtype = 'F'
               GROUP BY comp)
        WHERE bitand(x,3) = 3 OR bitand(x,5) = 5 OR bitand(x,9) = 9)

使用分析函数MAX() OVER ()的另一个修改,但逻辑相同

SELECT comp, vtype, vnum, vacc
  FROM (SELECT x.*,
               MAX (CASE WHEN (vacc BETWEEN '1544' AND '1567') THEN 1 ELSE 0 END) OVER (PARTITION BY comp) c1,
               MAX (CASE WHEN (comp = '55' AND vacc IN ('3019', '5222')) THEN 1 ELSE 0 END) OVER (PARTITION BY comp) c2,
               MAX (CASE WHEN (comp = '66' AND (vacc = '3013' OR vacc BETWEEN '6910' AND '6973')) THEN 1 ELSE 0 END) OVER (PARTITION BY comp) c4,
               MAX (CASE WHEN (comp NOT IN ('55', '66') AND vacc BETWEEN '3000' AND '3999') THEN 1 ELSE 0 END) OVER (PARTITION BY comp) c8
          FROM testtest2 x
         WHERE vtype = 'F')
 WHERE (c1 = 1 AND c2 = 1)
    OR (c1 = 1 AND c4 = 1)
    OR (c1 = 1 AND c8 = 1)