It is legal and well defined in SQLite. See the explain output below. This is 
because of the well-documented feature of SQLite that columns that are neither 
GROUPED BY nor aggregated will have a defined value.



First off, it is legal and perfectly normal to test for expressions containing 
columns that do not appear in the select list. Every JOIN with a foreign key 
that references a rowid does exactly that (nobody is interested in the 
internal, arbitrary rowid of the referenced table; just the facts please). The 
SQL Engine is expected to retrieve columns required to evaluate expressions.



The SQL standard defines WHERE as pertaining to the input rows and HAVING as 
pertaining to the output rows.



What you are really asking is:



SELECT count AS „count()“, a FROM (SELECT count() AS count, a, b FROM T GROUP 
BY a HAVING b > 0);



As already explained, the b value returned for each a will be (an arbitrary 
one) taken from the b values associated with this a. The fact that you are only 
interested in the first two columns of the result set does not preclude it 
containing addtional columns that are used because they are required to satisfy 
your query



asql> create temp table t (a int, b int, c int);

asql> .explain

asql> explain select count(),a from T group by a having b > 0;

addr  opcode         p1    p2    p3    p4             p5  comment

----  -------------  ----  ----  ----  -------------  --  -------------

0     Trace          0     0     0                    00  NULL

1     SorterOpen     1     3     0     Keyinfo(1,BINARY)  00  NULL

2     Integer        0     5     0                    00  clear abort flag

3     Integer        0     4     0                    00  indicate accumulator 
empty

4     Null           0     8     8                    00  NULL

5     Gosub          7     44    0                    00  NULL

6     Goto           0     49    0                    00  NULL

7     OpenRead       0     2     1     2              00  t

8     Rewind         0     15    0                    00  NULL

9     Column         0     0     10                   00  t.a

10    Sequence       1     11    0                    00  NULL

11    Column         0     1     12                   00  t.b

12    MakeRecord     10    3     13                   00  NULL

13    SorterInsert   1     13    0                    00  NULL

14    Next           0     9     0                    01  NULL

15    Close          0     0     0                    00  NULL

16    OpenPseudo     2     13    3                    00  NULL

17    SorterSort     1     48    0                    00  GROUP BY sort

18    SorterData     1     13    0                    00  NULL

19    Column         2     0     9                    20  NULL

20    Compare        8     9     1     Keyinfo(1,BINARY)  00  NULL

21    Jump           22    26    22                   00  NULL

22    Move           9     8     1                    00  NULL

23    Gosub          6     35    0                    00  output one row

24    IfPos          5     48    0                    00  check abort flag

25    Gosub          7     44    0                    00  reset accumulator

26    AggStep        0     0     1     count(0)       00  NULL

27    Column         2     0     2                    00  NULL

28    Column         2     2     3                    00  NULL

29    Integer        1     4     0                    00  indicate data in 
accumulator

30    SorterNext     1     18    0                    00  NULL

31    Gosub          6     35    0                    00  output final row

32    Goto           0     48    0                    00  NULL

33    Integer        1     5     0                    00  set abort flag

34    Return         6     0     0                    00  NULL

35    IfPos          4     37    0                    00  Groupby result 
generator entry point

36    Return         6     0     0                    00  NULL

37    AggFinal       1     0     0     count(0)       00  NULL

38    Integer        0     14    0                    00  NULL

39    Le             14    36    3     collseq(BINARY)  6c  NULL

40    Copy           1     15    0                    00  NULL

41    Copy           2     16    0                    00  NULL

42    ResultRow      15    2     0                    00  NULL

43    Return         6     0     0                    00  end groupby result 
generator

44    Null           0     2     0                    00  NULL

45    Null           0     3     0                    00  NULL

46    Null           0     1     0                    00  NULL

47    Return         7     0     0                    00  NULL

48    Halt           0     0     0                    00  NULL

49    Transaction    1     0     0                    00  NULL

50    VerifyCookie   1     1     0                    00  NULL

51    TableLock      1     2     0     t              00  NULL

52    Goto           0     7     0                    00  NULL

asql> insert into T values (1,2,1);

rows

----

1

asql> select count(),a from T group by a having b > 0;

coun  a

----  -------------

1   1

asql> insert into T values (2,0,3);

rows

----

1

asql> select count(),a from T group by a having b > 0;

coun  a

----  -------------

1         1

asql> insert into T values (2,1,3);

rows

----

1

asql> select count(),a from T group by a having b > 0;

coun  a

----  -------------

1     1

2     2

asql> insert into T values (2,0,4);

rows

----

1

asql> select count(),a from T group by a having b > 0;

coun  a

----  -------------

1     1



>-----Ursprüngliche Nachricht-----
>Von: James K. Lowden [mailto:jklow...@schemamania.org]
>Gesendet: Donnerstag, 08. Jänner 2015 03:56
>An: sqlite-users@sqlite.org
>Betreff: Re: [sqlite] New column in select will not mask column of the same 
>name in having clause and sqlite won't warn

>

>On Mon, 5 Jan 2015 06:39:42 +0000

>Hick Gunter <h...@scigames.at<mailto:h...@scigames.at>> wrote:

>

>> This is completely legal and well defined.

>>

>> HAVING is applied to the RESULT set of a SELECT.

>

>I beg to differ.  It's both invalid SQL and (therefore) undefined.

>Furthermore, it's illogical.  Consider:

>

>             create table T (a int, b int, c int);

>             insert into T values (1, 2, 1);

>

>             select count(*), a from T group by a having b > 0;

>

>Surely "select count(*), a from T" produces 1 row,

>

>             count(*)              a

>             --------  -

>                    1      1



It *outputs* 1 row with 2 fields



>

>but what does "having b > 0" mean if "HAVING is applied to the RESULT set of a 
>SELECT"?  There is no B!

>



Internally there is, because *you explicitly asked for it*



>If ad argumentum we say B refers to the B in the table, the question

>remains: how to interpret the having clause?  Is it TRUE If

>

>1.  there exists a row for a given value of A for which B > 0?

>2.  all rows for a given A have B > 0?

>

>It so happens (per http://sqlfiddle.com/#!5/34e8d/1) that sqlite accepts the 
>query and uses interpretation #2.  But that is arbitrary:

>HAVING is not a FORALL or EXISTS quantifier.  It has a single, clunky

>job: to test aggregates.



#3: a randomly selected b from the subset of records having a given a



If the single aggregate function is MIN or MAX, the returned value for b will 
be from one of the records where the minimum or maximum respectively occurs.



>

>Most SQL DBMSs reject the query outright.  As well they should, because it is 
>nonsensical.

>

>--jkl



___________________________________________
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: h...@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.
_______________________________________________
sqlite-users mailing list
sqlite-users@sqlite.org
http://sqlite.org:8080/cgi-bin/mailman/listinfo/sqlite-users

Reply via email to