2012-04-16 29 views
19

Bu question'u basitleştirilmiş ve genişletilmiş bir şekilde yeniden soruyorum. Bildiğim kadarıyla, MySQL'in söyleyebilirimSELECT sonuçları neden mysql ve sqlite arasında farklılık gösteriyor?

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

: sqlite kullanarak

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

, select deyimi döndürür:

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

ve MySQL döner

bu sql ifadeleri düşünün sonuçlar doğru ve sqlite yanlış. Aşağıdaki gibi sqlite ile real yayın yapmak için çalıştı ama yine de iki kayıt döndürür:

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

neden sqlite dönüş iki kayıtlar?

Hızlı güncelleme:

Ben son sqlite sürümü (3.7.11) ve yine iki kayıtları almak karşı bildiri koştu.

Diğer bir güncelleme:

Ben konu hakkında [email protected] bir e-posta gönderdi.

Kendim, VDBE ile oynuyordum ve ilginç bir şey buldum. not exists'un her döngüsünün yürütme izini bölüyorum (her bir avg grubu için bir tane). Biz açıkça bir şekilde r:4.5i:5 haline gelmiştir ne olması gerektiğini görüyoruz

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

:

üç ort gruplarını sahip olmak için, ben şu ifadeleri kullandı şimdi çalışıyorum

enter image description here

bunun neden olduğunu görmek için.

Final düzenlemek:

yüzden sqlite kaynak kodu ile yeterince oynuyoruz. o zaten bunu yapıyor gibi görünüyor gibi ben original developer tür dışarı bildireceğiz rağmen, şimdi çok daha iyi canavar anlıyorum:

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

İlginçtir en azından bana, öyle görünüyor ki, (daha yeni sürümleri bu Yukarıda belirtilen ilave bir test durumda kullanılan olarak kullanıyorum sürümü sonra bazı kez) birden fazla kayıt ekleme destekler taahhüt:

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

avg1' bulunamadı. Bunları 'MAX (T2.score) 've' MAX (T1.score) 'ile değiştirdim ve SQLite sonucunu verdi. Tabloyu "GERÇEK" ile oluşturduğumda MySQL sonucunu verdi. Belki de MySQL şemanınız sqlites'ten farklı mıdır? –

+0

@ ta.speot.is: avg (t2.score) olarak avg2' olarak (iki olay) olarak "ekliyor" ifadesini ekleyebilir misiniz? –

+0

Çalışmıyor. Oldukça emin SQL Server "WHERE", "GROUP BY" veya "HAVING" de takma adlar söz konusu olduğunda zar oynamaz. –

cevap

1

Ben sorguda bazı değişik karmaşa çalıştı.

Görünüşe göre, sqlite'ın iç içe geçmiş bir alandaki HAVING ifadelerinde kullanılma hataları vardır.İkinci olan altında örnek avg1 yılında

daima eşittir 5.0

Görünüş:

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

Bu seferki şey döndürür, ancak aşağıdaki sorgu yürütme hem kayıtları döndürür:

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

sqlite tickets list'da benzer bir hata bulamıyorum.

+1

Evet VDBE ile izleme yaparken çok benzer bir şey görüyorum. [email protected] adresine konuyla ilgili bir e-posta gönderdim. –

0

Bu sürümü denediniz mi? :

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

bu bir (veren olmalıdır Aynı sonuçlar):

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

sorgu, yerine HAVING maddesinde alt sorgunun, türetilmiş tablo ile ele alınabilir:

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

Sadece yaptım; sqlite aynı 2 kayıtları, aynı mysql 1 kayıt. –

+0

Evet, ikinci seçeneğiniz zaten bir cevap olarak hizmet ettim; lütfen bu sorunun başındaki bağlantıya bakın. –

+0

Orijinal sorgunun neden beklendiği gibi çalışmadığı konusunda, sanırım alt sorguların nasıl ele alınacağıyla ilgili bir hata. –

1

Bakalım Bu iki yol, ben 'değil' kurtulmak benim referans veritabanı

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

en, alt sorgunun içindeki mantık bazı geçelim olarak postgres 9.0 kullanacağız: (2 biz bir kartezyen yapıyoruz birincil sorgudan her satırda karşı her satırı değerlendirir eğer bir sahip maddesinin içinde bu ilişkili alt sorgu yaptığınızda aslında ne anlama geliyor -)

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

yüzden kendinize sormanız var katıl ve ben işaret parmağı olmalıyız sanmıyorum SQL motorunda rs. Maksimum ortalamasının altında olmasına her satır istiyorsanız

Ne dilemesi gereken: Ben üretmek ve onu `` şikayet avg2` ve ne SQL Server SQL bu koştum Sadece tekmelemek için

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

Sorumluluktaki bu seçim ifadesi gerçekten anlaşılması zor değil; Ben sadece bunu belirsiz iddia ve farklı teknolojiler –

+0

istiyorum; ve ayrıca sqlite'ın ana geliştiricisinin [email protected] adresine gönderdiğim e-postaya tepki olarak değişiklikler yaptığı anlaşılıyor. –

+0

O MySQL, MS SQL ve şimdi Postgres için belirsiz değil gibi görünüyor karşısında belirsiz bir sonuç verecektir doğru sonucu ;-) –

İlgili konular