简体   繁体   中英

SQL: simplify and, or query on multiple columns

I have a table named employe with following content

id A B C D E F G
1  8 4 6 3 2 5 2
1  7 3 1 2 1 3 7
3  9 2 3 3 2 6 1
4  6 1 2 4 5 5 7
4  6 4 6 3 2 5 2

I do a query like this

employe.where( 
   A > 7 & 
(

 (C<3 & D<3 & E<3 & F<3 & G<3) 
|(B<3 & D<3 & E<3 & F<3 & G<3)
|(B<3 & C<3 & E<3 & F<3 & G<3)  
|(B<3 & C<3 & D<3 & F<3 & G<3)
|(B<3 & C<3 & D<3 & E<3 & G<3)
|(B<3 & C<3 & D<3 & E<3 & F<3)

)
)

Is there any way to simplify the above query? Because I have more than 20 columns in my table and I have do the above query for all columns. It looks ugly and same code in every line. Even if I could something like this would look nice

q1 = [C, D, E, F, G]
q2 = [B, D, E, F, G]
q3 = [B, C, E, F, G]
q4 = [B, C, D, F, G]
q5 = [B, C, D, E, G]
q6 = [B, C, D, E, F]
employe.where( 
   A > 7 & 
(
  q1<3 | q2<3 | q4<4 | q5<3 | q6<3
)
)

I don't have MySQL to check, but is it possible to do something like:

SELECT * FROM @employee e
INNER JOIN (SELECT id, A, 
CASE WHEN a < 3 THEN 0 ELSE 1 END +  
CASE WHEN b < 3 THEN 0 ELSE 1 END +  
CASE WHEN c < 3 THEN 0 ELSE 1 END +  
CASE WHEN d < 3 THEN 0 ELSE 1 END +  
CASE WHEN e < 3 THEN 0 ELSE 1 END +  
CASE WHEN f < 3 THEN 0 ELSE 1 END +  
CASE WHEN g < 3 THEN 0 ELSE 1 END as cnt from @employee) c  
on e.id = c.id
WHERE e.A > 7 AND c.cnt < 3

If I understand you correctly you are trying to find instances of one column where it is greater than 7, where at least four of the other five columns are less than three. My example achieves this (for all columns) by a simple trick of logic. If you count all the instances of AG that are not less than 3 and check that for any column this is less than 3 where that column is > 7, then you know the others are maximally one not less than 3, since the column itself is one of the 2 that are not less than 3.

Expanding the example for all columns you then get

SELECT * FROM @employee e
INNER JOIN (SELECT id, 
CASE WHEN a < 3 THEN 0 ELSE 1 END +  
CASE WHEN b < 3 THEN 0 ELSE 1 END +  
CASE WHEN c < 3 THEN 0 ELSE 1 END +  
CASE WHEN d < 3 THEN 0 ELSE 1 END +  
CASE WHEN e < 3 THEN 0 ELSE 1 END +  
CASE WHEN f < 3 THEN 0 ELSE 1 END +  
CASE WHEN g < 3 THEN 0 ELSE 1 END as cnt from @employee) c  
on e.id = c.id
WHERE (e.A > 7 OR e.B > 7 OR e.C > 7 OR e.D > 7 OR e.F > 7 or e.G > 7) 
AND c.cnt < 3

If all values (columns) from the list must be less than 3, then the greatest value in this list must be also less than 3, so you can use greatest function, something like:

Where
  Greatest( c, d, e, f, g ) < 3
  Or
  Greatest( b, d, e, f, g ) < 3
  Or
  Greatest( b, c, d, e, f ) < 3
  Or
  .....

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM