Why does SELECT results differ between mysql and sqlite?

前端 未结 3 1333
你的背包
你的背包 2021-02-12 13:41

I\'m re-asking this question in a simplified and expanded manner.

Consider these sql statements:

create table foo (id INT, score INT);

insert into foo v         


        
相关标签:
3条回答
  • 2021-02-12 14:16

    Lets look at this two ways, i'll use postgres 9.0 as my reference database

    (1)

    -- select rows from foo 
    
    select T1.id, avg(T1.score) avg1
    from foo T1
    group by T1.id
    -- where we don't have any rows from T2
    having  not exists (
    -- select rows from foo
    select T2.id, avg(T2.score) avg2
    from foo T2
    group by T2.id
    -- where the average score for any row is greater than the average for 
    -- any row in T1
    having avg2 > avg1);
    
     id  |        avg1        
    -----+--------------------
     106 | 4.5000000000000000
    (1 row)
    

    then let's move some of the logic inside the subquery, getting rid of the 'not' : (2)

    -- select rows from foo 
    select T1.id, avg(T1.score) avg1
    from foo T1
    group by T1.id
    -- where we do have rows from T2
    having  exists (
    -- select rows from foo
    select T2.id, avg(T2.score) avg2
    from foo T2
    group by T2.id
    -- where the average score is less than or equal than the average for any row in T1
    having avg2 <= avg1);
    -- I think this expression will be true for all rows as we are in effect doing a
    --cartesian join 
    -- with the 'having' only we don't display the cartesian row set
    
     id  |        avg1        
    -----+--------------------
     106 | 4.5000000000000000
     107 | 4.0000000000000000
    (2 rows)
    

    so you have got to ask yourself -- what do you actually mean when you do this correlated subquery inside a having clause, if it evaluates every row against every row from the primary query we are making a cartesian join and I don't think we should be pointing fingers at the SQL engine.

    if you want every row that is less than the maximum average What you should be saying is:

    select T1.id, avg(T1.score) avg1 
    from foo T1 group by T1.id
    having avg1 not in 
    (select max(avg1) from (select id,avg(score) avg1 from foo group by id)) 
    
    0 讨论(0)
  • 2021-02-12 14:17

    Have you tried this version? :

    select T1.id, avg(T1.score) avg1
    from foo T1
    group by T1.id
    having not exists (
        select T2.id, avg(T2.score) avg2
        from foo T2
        group by T2.id
        having avg(T2.score) > avg(T1.score));
    

    Also this one (which should be giving same results):

    select T1.*
    from
      ( select id, avg(score) avg1
        from foo 
        group by id
      ) T1
    where not exists (
        select T2.id, avg(T2.score) avg2
        from foo T2
        group by T2.id
        having avg(T2.score) > avg1);
    

    The query can also be handled with derived tables, instead of subquery in HAVING clause:

    select ta.id, ta.avg1
    from 
      ( select id, avg(score) avg1
        from foo
        group by id
      ) ta
      JOIN
      ( select avg(score) avg1
        from foo 
        group by id
        order by avg1 DESC
        LIMIT 1
      ) tmp
      ON tmp.avg1 = ta.avg1 
    
    0 讨论(0)
  • 2021-02-12 14:21

    I tried to mess with some variants of query.

    It seems, like sqlite has errors in using of previous declared fields in a nested HAVING expressions.

    In your example avg1 under second having is always equal to 5.0

    Look:

    select T1.id, avg(T1.score) avg1
    from foo T1
    group by T1.id
    having not exists (
        SELECT 1 AS col1 GROUP BY col1 HAVING avg1 = 5.0);
    

    This one returns nothing, but execution of the following query returns both records:

    ...
    having not exists (
        SELECT 1 AS col1 GROUP BY col1 HAVING avg1 <> 5.0);
    

    I can not find any similar bug at sqlite tickets list.

    0 讨论(0)
提交回复
热议问题