Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to OR together the WHERE and HAVING clauses in a SQL query?

Tags:

sql

Suppose that I have a SQL query

SELECT Label1, Label2, SUM(number) as MySum
FROM MyTable
GROUP BY Label1, Label2

and it gives me some results like

Label1 | Label2 | MySum 
-------+--------+------
Foo    | Bar    |   100
Foo    | Baz    |  -100
NotFoo | Bar    |   100
NotFoo | Baz    |  -100

I can put a WHERE and HAVING clause to filter down the results

SELECT Label1, Label2, SUM(number) as MySum
FROM MyTable
WHERE Label1 = 'Foo'
GROUP BY Label1, Label2
HAVING MySum > 0

and this gives me the results

Label1 | Label2 | MySum 
-------+--------+------
Foo    | Bar    |   100

The WHERE and HAVING are ANDed implicitly together.

Is there a syntax for something like

SELECT Label1, Label2, SUM(number) as MySum
FROM MyTable
WHERE Label1 = 'Foo'
GROUP BY Label1, Label2
OR HAVING MySum > 0

giving the results

Label1 | Label2 | MySum 
-------+--------+------
Foo    | Bar    |   100
Foo    | Baz    |  -100
NotFoo | Bar    |   100

?

I could do

SELECT Label1, Label2, SUM(number) as MySum
FROM MyTable
WHERE Label1 = 'Foo'
GROUP BY Label1, Label2

UNION 

SELECT Label1, Label2, SUM(number)
FROM MyTable
GROUP BY Label1, Label2
HAVING MySum > 0

Disadvantage: This can be inefficient as the database has to work out the Foo | Bar | 100 line twice, find that it is a duplicate and then throw it away.

I could also write

SELECT Label1, Label2, SUM(number) as MySum
FROM MyTable
WHERE Label1 = 'Foo'
GROUP BY Label1, Label2

UNION ALL

SELECT Label1, Label2, SUM(number)
FROM MyTable
WHERE Label1 <> 'Foo'
GROUP BY Label1, Label2
HAVING MySum > 0

Disadvantage: It is starting to become less easy to understand at first glance (possibly the least bad disadvantage).

Or

SELECT Label1, Label2, SUM(number) as MySum
FROM MyTable
GROUP BY Label1, Label2
HAVING MySum > 0
OR Label1 = 'Foo'

Disadvantage: This will make the database could do a lot of extra work aggregating up lots of non Foo labels.

like image 556
Jonny Avatar asked Nov 10 '22 15:11

Jonny


1 Answers

The last of your answers is fine:

SELECT Label1, Label2, SUM(number) as MySum
FROM MyTable
GROUP BY Label1, Label2
HAVING MySum > 0
OR Label1 = 'Foo'

You've said that there is extra work here, but that isn't the case, as you have to do that aggregating to find out if MySum>0 for the non Label1='Foo' rows to determine if they should be included.

like image 193
Jon Egerton Avatar answered Nov 26 '22 18:11

Jon Egerton