The main difference between HAVING and WHERE ist that WHERE operates on the 
input set and HAVING operates on the output set.

If your condition requires computing an aggregate, then HAVING is a viable 
method of avoiding a subquery that needs to repeatedly scan the input table:

SELECT currency,price FROM Prices p WHERE day = (SELECT max(day) from Prices 
where currency=p.currency);

explain query plan SELECT currency,price FROM Prices p WHERE day = (SELECT 
max(day) from Prices where currency=p.currency);
sele  order          from  deta
----  -------------  ----  ----
0     0              0     SCAN TABLE Prices AS p (~500000 rows)
0     0              0     EXECUTE CORRELATED SCALAR SUBQUERY 1
1     0              0     SEARCH TABLE Prices USING AUTOMATIC COVERING INDEX 
(currency=?) (~1 rows)

explain query plan SELECT currency, price FROM Prices GROUP BY currency HAVING 
day = max(day);
sele  order          from  deta
----  -------------  ----  ----
0     0              0     SCAN TABLE Prices (~1000000 rows)
0     0              0     USE TEMP B-TREE FOR GROUP BY

If your condition does not require computing an aggregate, just use WHERE.

SELECT currency,price from Prices WHERE day=2;

To find the latest price on or before day 3:

SELECT currency,price from Prices WHERE day <= 3 GROUP by currency HAVING day = 
max(day);

explain query plan SELECT currency,price from Prices WHERE day <= 3 GROUP by 
currency HAVING day = max(day);
sele  order          from  deta
----  -------------  ----  ----
0     0              0     SCAN TABLE Prices (~333333 rows)
0     0              0     USE TEMP B-TREE FOR GROUP BY

Note that this is without any defined indexes. Plans may change depending on 
indexes added, and the cardinality of constrained fields.




-----Urspr?ngliche Nachricht-----
Von: Rowan Worth [mailto:rowanw at dugeo.com]
Gesendet: Dienstag, 29. September 2015 09:06
An: General Discussion of SQLite Database
Betreff: [sqlite] Is it legal SQL to select a specific row of a group via a 
HAVING clause?

Hi guys,

Imagine a DB storing a history of currency exchange rate info.

CREATE TABLE Prices (
    id INTEGER PRIMARY KEY,
    day INTEGER,
    currency TEXT,
    price FLOAT);

Assume 'day' increases monotonically and there is at most one price recorded 
per currency per day - if you want to know the latest prices, is this legal?

SELECT currency, price FROM Prices GROUP BY currency HAVING time = MAX(time);

I've seen this approach used and my reading of 
https://www.sqlite.org/lang_select.html#resultset hasn't left me confident that 
it is correct SQL, but in practice it seems to work fine... eg:

insert into Prices (day, currency, price) values (1, 'EUR', 1.86); insert into 
Prices (day, currency, price) values (1, 'USD', 1.20); insert into Prices (day, 
currency, price) values (2, 'EUR', 1.92); insert into Prices (day, currency, 
price) values (2, 'USD', 1.18); insert into Prices (day, currency, price) 
values (3, 'USD', 1.24);
/* price for EUR on day 3 intentionally left blank */

sqlite> SELECT currency, price FROM Prices GROUP BY currency HAVING day
sqlite> =
MAX(day);
EUR|1.92
USD|1.24

MIN also seems to work:

sqlite> SELECT currency, price FROM Prices GROUP BY currency HAVING day
sqlite> =
MIN(day);
EUR|1.86
USD|1.2

As an aside, the query definitely doesn't work to get prices for a specific
day:

sqlite> SELECT currency, price FROM Prices GROUP BY currency HAVING day
sqlite> = 2;
EUR|1.92

I think the following explains the last result:

> If a HAVING clause is a non-aggregate expression, it is evaluated with
> respect to an arbitrarily selected row from the group.

And the arbitrary row for EUR just happened to be day=2 here. But the 
documentation doesn't mention non-aggregate queries with a group by clause...


> If the HAVING clause is an aggregate expression, it is evaluated
> across
all
> rows in the group.

I'm not sure how to interpret this in the context of the "day = MAX(day)"
expression though - does "evaluated across all rows" mean that rows excluded by 
the clause are discarded?

If not then I suspect this query is not legit... but I don't feel I've 
understood everything so any clarification is appreciated!

Cheers,
-Rowan
_______________________________________________
sqlite-users mailing list
sqlite-users at mailinglists.sqlite.org
http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users


___________________________________________
 Gunter Hick
Software Engineer
Scientific Games International GmbH
FN 157284 a, HG Wien
Klitschgasse 2-4, A-1130 Vienna, Austria
Tel: +43 1 80100 0
E-Mail: hick at scigames.at

This communication (including any attachments) is intended for the use of the 
intended recipient(s) only and may contain information that is confidential, 
privileged or legally protected. Any unauthorized use or dissemination of this 
communication is strictly prohibited. If you have received this communication 
in error, please immediately notify the sender by return e-mail message and 
delete all copies of the original communication. Thank you for your cooperation.


Reply via email to