I have a single table ledrow
Which has 4 columns.
I want to only select rows where they have (per vnum
and comp
) rows that are in both sets of logic.
English Explanation
So for example out of all the data below, explaining the rows in the expected output is as follows:
For comp
99 we have results as all of the vacc
numbers fall into either of the sets of logic:
The vacc
is either BETWEEN '1544' AND '1567'
OR the vacc
is BETWEEN '3000' AND '3999'
However for example comp
77 rows aren't output because even though:
comp vtype vnum vacc
77 F 1369 3400
77 F 1369 3402
Comes under the second part of the logic the rest of the rows don't fall under any:
comp vtype vnum vacc
77 F 1369 1510
77 F 1369 2620
77 F 1369 2620
77 F 1369 2620
77 F 1369 1650
This is because to be part of the output I want all rows per comp MUST fall in either parts of the logic per comp.
I have tried the following code but cannot get my expected output.
Current Code:
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'
Expected Output:
comp vtype vnum vacc
99 F 1369 1564
99 F 1369 2610
99 F 1369 2610
99 F 1369 3601
99 F 1369 3600
Full Table ( 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
Edit
So for each vnum
and comp
it needs to satisfy both of the two conditions in the WHERE clause.
So for comp
99
which has to satisfy both the conditions:
((comp NOT IN ('55', '66') AND vacc BETWEEN '1544' AND '1567') AND (comp NOT IN ('55', '66') AND (vacc BETWEEN '3000' AND '3999'))))
If I understood what you were trying to do, then this should work :
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'))
You specified each of the first conditions twice, which is not necessary as they are correct to both of the next conditions.
(comp not IN('55','66') AND Cond1) AND/OR (comp not IN('55','66') AND Cond2)
Equals to:
comp not IN('55','66') AND (Cond1 AND/OR Cond2)
EDIT: You can try something like this:
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'
This will basically give an indication to each row, first condition is 1,2
corresponding to the part of this condition the satisfied , second one is 3,4
and third is 5,6
. Then you check that each group only has 1+2 or 3+4 or 5+6 with the HAVING
clause with MAX()
and MIN()
which will assure that this comp
satisfy both conditions.
This solution works only for rows that satisfy both conditions, not only one of them. If only one of them is enough, that change the having clause to this:
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)
May be I have understood what you want :)
We make every special conditions per comp (group by comp) like a bit in a byte (1,2,4,8) and then add them. Than we choose only the combination what we want. (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)
Another modification with analytic function MAX() OVER () , but the same logic
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)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.