Bu sorgu için doğru sonuç nedir?


20

Bu yapbozun yorumlarına rastladım.

CREATE TABLE r (b INT);

SELECT 1 FROM r HAVING 1=1;

SQL Server ve PostgreSQL 1 satır döndürür.

MySQL ve Oracle sıfır satır döndürür.

Hangisi doğru? Yoksa ikisi de eşit derecede geçerli mi?


Güzel bir bulmaca. Bence doğru 1 satır dönmek. SQL-Server kendisiyle çelişiyor çünkü SELECT COUNT(*) FROM r;1 satır döndürüyor (ile 0), SELECT COUNT(*) FROM r GROUP BY ();hiçbir satır döndürmüyor.
ypercubeᵀᴹ

1
Daha fazla istemek? SELECT 1 WHERE 1=0 HAVING 1=1;. SQL Server ve PostgreSQL hala bir satır döndürüyor. Oracle, DUAL DUAL istiyor ve hiç satır döndürmüyor. MySQL, ne FROM DUAL ile ne de onsuz derlenmez .
Andriy M

1
@AndriyM Bilinmeyen bazı nedenlerden ötürü "ikili" ve "HAVING" MySQL'de iyi oynamıyor. (Güzel bulgu). Ancak eşdeğer çalışır: SELECT 1 AS t FROM (SELECT 1) tmp WHERE 1=0 HAVING 1=1; 1 satır-çift değil ve 0 satır döndürür.
ypercubeᵀᴹ

1
@SQLKiwi - Spesifikasyondan bu pasaj ne olacak? "TE hemen içermiyorsa <group by clause>, o zaman “GROUP BY ()”örtülü olduğunu.". Her iki sorgu da aynı sonuçları döndürmemeli mi?
Martin Smith

1
Ancak bunlara katılmıyorum (Oracle, sorguları HAVINGfarklı şekilde yürütüyor ): SQl-fiddle 2: HAVING işleri farklı kılıyor
ypercubeᵀᴹ

Yanıtlar:


17

Standartlara göre:

SELECT 1 FROM r HAVING 1=1

anlamına geliyor

SELECT 1 FROM r GROUP BY () HAVING 1=1

Alıntı ISO / IEC 9075-2: 2011 7.10 Sözdizimi Kural 1 (HAVING yan tümcesinin tanımının bir parçası):

Izin HColmak <having clause>. Izin TEolmak <table expression>hemen içerdiğini HC. Eğer TEhemen bir içermiyor <group by clause>, ardından “ GROUP BY ()” örtük olduğunu. Izin vermek hemen içerdiği Ttarafından tanımlanan tablonun tanımlayıcı olmak ve sonuç olsun .<group by clause> GBCTERGBC

Tamam o kadar açık ki.


İddia: 1=1gerçek arama koşulu. Bunun için alıntı yapmayacağım.


şimdi

SELECT 1 FROM r GROUP BY () HAVING 1=1

eşittir

SELECT 1 FROM r GROUP BY ()

Atıf ISO / IEC 9075-2: 2011 7.10 Genel Kural 1:

<search condition>Her grup için değerlendirilir R. Sonuç <having clause>, sonucunun <search condition>Doğru olduğu R gruplarının gruplandırılmış bir tablosudur .

Mantık: Arama koşulu daima doğru Rolduğu için sonuç, grubun ifadeye göre sonucudur.


Aşağıdaki genel kurallar 7.9'dan (GROUP BY CLAUSE'ın tanımı) bir alıntıdır.

1) Hayır <where clause>belirtilirse, bir öncekinin Tsonucu olsun <from clause>; aksi takdirde, bir öncekinin Tsonucu olsun <where clause>.

2) Durum:

a) Hiçbir gruplama sütunu yoksa, sonucunun sonucu tek grup olarak <group by clause>oluşan gruplandırılmış tablodur T.

Böylece şu sonuca varabiliriz:

FROM r GROUP BY ()

sıfır satır içeren bir gruptan oluşan gruplandırılmış bir tablo ile sonuçlanır (R boş olduğu için).


Sorgu Spesifikasyonu (diğer adıyla SELECT ifadesi) tanımlayan 7.12 Genel Kurallarından bir alıntı:

1) Durum:

a) TGruplandırılmış bir tablo değilse, [...]

b) TGruplandırılmış bir tablo ise,

Durum:

i) T0 (sıfır) grup varsa TEMP'nin boş bir tablo olmasına izin verin.

Eğer ii) Tbir veya daha fazla grup yer alır, daha sonra her bir <value expression>her bir gruba uygulanan Tbir tablo elde TEMPait Msıraları, burada Mgrupların sayısıdır T. iTEMP inci kolon değerlendirilmesi ile elde edilen değerleri içerir ith <value expression>. [...]

2) Durum:

Bir) <set quantifier> DISTINCTbelirtilmemişse, o sonucu <query specification>olduğunu TEMP.

Bu nedenle, tablonun bir grubu olduğundan, bir sonuç satırına sahip olması gerekir.

Böylece

SELECT 1 FROM r HAVING 1=1

1 satır sonuç kümesi döndürmelidir.

QED


+1 Bütün bu belaya gittiğin için teşekkürler! @Ypercube dediği gibi SQL Server burada kendisiyle çelişiyor gibi görünmektedir. sıfır satır döndürür, ancak alıntıladığınız pasaj bu noktada oldukça açıktır.
Martin Smith

Standardı nerede bulduğunuzu sorabilir miyim? '
Kitaplığımda' derseniz

Teknik olarak standardın kendisinden ziyade Nihai Uluslararası Taslak Standardını kullandım. ISO / IEC kurallarına göre, FDIS ile nihai standart arasında yalnızca editoryal (teknik olmayan) değişikliklere izin verilir. Standart birden fazla parçaya tükürülür. Bölüm 1 , Bölüm 2 , Bölüm 4 ...
Kevin Cathcart

Bölüm 11 ve Bölüm 14 . Kısım 3,9,10 ve 13 2011'de güncellenmediği için önceki sürümleri geçerlidir. Parça 12 yoktur. Benzer şekilde parça 5-8 de yoktur. Her parçanın ne içerdiğinin açıklaması için Sql: 2011 veya Kısım 1'in Wikipedia sayfasına bakın .
Kevin Cathcart

7

Bir HAVINGmadde olduğunda, bir madde olmadan WHERE:

SELECT 1 FROM r HAVING 1=1;

... o GROUP BY ()zaman örtük. Bu nedenle, sorgu şuna eşdeğer olmalıdır:

SELECT 1 FROM r GROUP BY () HAVING 1=1;

... tablonun tüm satırlarını tek bir grupta gruplamalı (tablonun hiç satırı olmasa bile - yine de 0 satırlık bir gruptur) ve 1 satır döndürür. Bu durumla HAVINGbirlikte, Truebundan sonra hiçbir etkisi olmamalıdır.


Farklı bir açıdan, böyle bir sorgu kaç satır döndürmelidir?

SELECT COUNT(*), MAX(b) FROM r;

Bir, sıfır veya "tablonun boş olup olmamasına bağlı olarak sıfır veya bir"?

Bence bir satır, kaç satır olursa olsun r.


Temel sorun, "tablonun hiç satırı olmasa bile, yine de 0 satırlık bir grup" olduğunun gerçekten doğru olup olmadığıdır. Ve standart bu konuda açıktır: "Hiçbir gruplama sütunu yoksa, o zaman ... T, tek grubu olarak oluşan gruplandırılmış tablodur". (ve bu, T boş olsa bile geçerlidir - bu yüzden gerçekten bir grup vardır.) Dahası, sahip olma koşulu, koşulun her gruba uygulandığını belirtir (bu nedenle örnekte bir kez). Muhtemelen SUM ve COUNT öğesinin boş T'ler için bile bir satır döndürmesini sağladılar.
Erwin Smout

+1 (daha önce!) Mantığınız Kevin'inkiyle aynı olsa da, spesifikasyondan alıntılar yüzünden cevabını kabul ettim. Teşekkürler!
Martin Smith

@MartinSmith. Thnx. Tembel olmaktan :)
ypercubeᵀᴹ

@ ypercube: benden +1. Cevabınızı yanlış yapacak gizli bir yerde gizli bir kelime olmadığını kanıtlamak için spesifikasyondan çekmek için ekstra zaman ayırmaya karar verdim. Ama bunu yaptıktan sonra, tam bir cevap olarak da gönderebilirim. Ben de yaptım.
Kevin Cathcart

3
@ErwinSmout: Tabii ki hayır. Ancak bu ABD telif hakkı yasası uyarınca adil kullanım kapsamındadır. Çalışmanın analizi (yani eleştiri) bağlamında, eğitim amaçlı olarak, işin satılma yeteneği üzerinde ihmal edilebilir bir etkisi olan nispeten küçük bölümler.
Kevin Cathcart

3

Gördüğüm kadarıyla, SQLServer ve PostgerSQL tabloya hiç bakma zahmetine benzemiyor:

CREATE TABLE r (b INT);
insert into r(b) values (1);
insert into r(b) values (2);
SELECT 1 FROM r HAVING 1=1;

ayrıca yalnızca bir satır döndürür. SQLServer belgeleri diyor olsa da

GROUP BY kullanılmadığında HAVING bir WHERE yantümcesi gibi davranır.

bu durumda bu doğru değildir - WHERE 1=1bunun yerine HAVINGuygun sayıda satır döndürür. Optimize edici hata (ya da en azından belge hatası) olduğunu söyleyebilirim ... SQLServer planı 'sürekli tarama' durumunda HAVINGve 'tablo tarama' gösterir WHERE...

Oracle ve Mysql davranışı benim için daha mantıklı ve doğru görünüyor ...


1
SQL Server'ın masaya bakmaması haklısınız. Yürütme planının sürekli bir taraması vardır ve tabloya bile başvurmaz. Sadece SQL Server olsaydı, sadece bir hataya koyardım ama sadece SQL Server olmadığı için burada gerçek bir belirsizlik olup olmadığını merak ediyorum.
Martin Smith

PostgreSQL, SQLServer ile aynı sonuçları gösterir ve explain"Sonuç (satırlar = 1) ..." çıkışından anlatabildiğim kadarıyla ve "NEREDE" için "Seq Scan" de tabloya bakmaz. .. Sanırım TSQL ve PostgreSQL'de "FROM" un zorunlu olmaması bir şekilde ilgili. Mysql'in de gerektirmediğini biliyorum, ancak destekledikleri için dual, muhtemelen sorguyu biraz farklı ayrıştırıyorlar. Kabul ediyorum, bir spekülasyon gibi geliyor, ama umarım bir anlam ifade eder.
a1ex07
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.