2012-04-16 65 views
19

Tôi đang yêu cầu lại question này theo cách đơn giản và được mở rộng.Tại sao kết quả SELECT khác nhau giữa mysql và sqlite?

Xem xét các báo cáo sql:

create table foo (id INT, score INT); 

insert into foo values (106, 4); 
insert into foo values (107, 3); 
insert into foo values (106, 5); 
insert into foo values (107, 5); 

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 avg2 > avg1); 

Sử dụng SQLite, lợi nhuận select tuyên bố:

id   avg1  
---------- ---------- 
106   4.5  
107   4.0  

và trả về mysql:

+------+--------+ 
| id | avg1 | 
+------+--------+ 
| 106 | 4.5000 | 
+------+--------+ 

Theo như tôi có thể nói, của mysql kết quả là chính xác và sqlite không chính xác. Tôi cố gắng để đúc để real với sqlite như trong sau nhưng nó sẽ trả về hai kỷ lục vẫn:

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

Tại sao sqlite trở lại hai kỷ lục?

nhanh cập nhật:

tôi chạy báo cáo kết quả so với phiên bản sqlite mới nhất (3.7.11) và vẫn nhận được hai hồ sơ.

Một cập nhật:

tôi đã gửi một email đến [email protected] về vấn đề này.

Bản thân tôi, tôi đã chơi với VDBE và tìm thấy điều gì đó thú vị. Tôi chia dấu vết thực hiện của mỗi vòng lặp not exists (một cho mỗi nhóm avg).

Để có ba nhóm trung bình, tôi đã sử dụng các báo cáo sau:

create table foo (id VARCHAR(1), score INT); 

insert into foo values ('c', 1.5); 
insert into foo values ('b', 5.0); 
insert into foo values ('a', 4.0); 
insert into foo values ('a', 5.0); 

PRAGMA vdbe_listing = 1; 
PRAGMA vdbe_trace=ON; 

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

Chúng tôi rõ ràng thấy rằng bằng cách nào đó những gì cần được r:4.5 đã trở thành i:5:

enter image description here

bây giờ tôi đang cố gắng để xem tại sao lại thế.

cuối cùng chỉnh sửa:

Vì vậy, tôi đã chơi đủ với mã nguồn sqlite. Tôi hiểu con thú tốt hơn bây giờ, mặc dù tôi sẽ cho các original developer loại nó ra khi ông dường như đã được làm việc đó:

http://www.sqlite.org/src/info/430bb59d79

Điều thú vị là, với tôi ít nhất, có vẻ như các phiên bản mới hơn (một số lần sau khi phiên bản tôi đang sử dụng) hỗ trợ chèn nhiều bản ghi được sử dụng trong một trường hợp thử nghiệm bổ sung trong nói trên cam kết:

CREATE TABLE t34(x,y); 
INSERT INTO t34 VALUES(106,4), (107,3), (106,5), (107,5); 
+0

Chỉ cần cho đá Tôi chạy này để SQL gì SQL Server sẽ tạo ra và nó phàn nàn 'avg2' và' avg1' không tồn tại. Tôi đã thay thế chúng bằng 'MAX (T2.score)' và 'MAX (T1.score)' và nó cho kết quả SQLite. Khi tôi tạo ra bảng với 'điểm số REAL' nó đã cho kết quả MySQL. Có lẽ lược đồ MySQL của bạn khác với sqlites? –

+0

@ ta.speot.is: bạn có thể thử thêm 'as' như trong' avg (T2.score) làm avg2' (hai lần xuất hiện) không? –

+0

Không hoạt động. Khá chắc chắn SQL Server không chơi xúc xắc khi nói đến việc sử dụng bí danh trong 'WHERE',' GROUP BY' hoặc 'HAVING'. –

Trả lời

1

tôi cố gắng để gây rối với một số biến thể của truy vấn.

Dường như, sqlite có lỗi khi sử dụng các trường được khai báo trước trong một biểu thức lồng nhau HAVING.

Trong ví dụ của bạn avg1 dưới có thứ hai luôn bằng 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); 

Cái này trả về không có gì, nhưng thực hiện các truy vấn sau trả cả hồ sơ:

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

Tôi không thể tìm thấy bất kỳ lỗi tương tự nào tại số sqlite tickets list.

+1

Có, tôi thấy một cái gì đó rất giống với khi truy tìm với VDBE. Tôi đã gửi [email protected] một email về vấn đề này. –

0

Bạn đã thử phiên bản này chưa? :

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)); 

Cũng một này (mà phải được đưa ra kết quả tương tự):

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); 

Truy vấn cũng có thể được xử lý với các bảng có nguồn gốc, thay vì subquery trong HAVING khoản:

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

Tôi vừa làm; cùng 2 bản ghi trong sqlite, cùng 1 bản ghi trong mysql. –

+0

Có tùy chọn thứ hai của bạn tôi đã từng là câu trả lời; vui lòng xem câu hỏi tôi đã liên kết ở đầu câu hỏi này. –

+0

Tại sao truy vấn ban đầu không hoạt động như mong đợi, tôi cho rằng đó là lỗi, liên quan đến cách truy vấn con được xử lý. –

1

Cho phép xem xét hai cách này, tôi sẽ sử dụng postgres 9.0 như cơ sở dữ liệu tài liệu tham khảo của tôi

(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) 

sau đó hãy di chuyển một số logic bên trong subquery, loại bỏ các 'không': (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) 

vì vậy bạn có được để tự hỏi mình - điều gì làm bạn thực sự có ý nghĩa khi bạn làm subquery tương quan này bên trong một có điều khoản, nếu nó đánh giá mỗi hàng với mỗi hàng từ các truy vấn chính mà chúng tôi đang làm cho một Descartes tham gia và tôi không nghĩ chúng ta nên chỉ ngón tay rs tại công cụ SQL.

nếu bạn muốn mỗi hàng đó là ít hơn mức trung bình tối đa gì bạn nên nói là:

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

Câu lệnh chọn đó trong câu hỏi của tôi thực sự không khó hiểu; Tôi chỉ muốn kết quả chính xác ;-) –

+0

Tôi cho rằng nó không rõ ràng và sẽ cung cấp kết quả không xác định trên các công nghệ khác nhau –

+0

Dường như nó không mơ hồ với MySql, MS Sql và bây giờ là Postgres; và có vẻ như nhà phát triển chính của sqlite đang thực hiện thay đổi trong phản ứng với email mà tôi đã gửi tới [email protected] –

Các vấn đề liên quan