MySQL neden SELECT takma adlarını kullanmanıza izin veriyor?


14

SQL'de, bildiğim kadarıyla, kavramsal yorumlama sırası olan mantıksal sorgu işleme sırası FROM ile şu şekilde başlar:

  1. DAN
  2. NEREDE
  3. GRUPLA
  4. HAVING
  5. SEÇ
  6. TARAFINDAN SİPARİŞ

Bu listeyi izleyerek neden WHERE yan tümcesinde SELECT takma adlarına sahip olamayacağınızı görmek kolaydır, çünkü takma ad henüz oluşturulmamıştır. T-SQL (SQL Server) bunu kesinlikle takip eder ve SELECT'i geçene kadar SELECT takma adlarını kullanamazsınız.

Ancak MySQL'de SELECT takma adlarını HAVING yan tümcesinde kullanmak mümkündür (mantıksal olarak) SELECT yan tümcesinden önce işlenmesi gerekir. Bu nasıl mümkün olabilir?

Bir örnek vermek gerekirse:

SELECT YEAR(orderdate), COUNT(*) as Amount
FROM Sales.Orders
GROUP BY YEAR(orderdate) 
HAVING Amount>1;

T-SQL'de ifade geçersiz (HAVING SELECT takma adına atıfta bulunduğundan Amount) ...

Msg 207, Level 16, State 1, Line 5
Invalid column name 'Amount'.

... ama MySQL'de gayet iyi çalışıyor.

Buna dayanarak, merak ediyorum:

  • MySQL kullanıcıya yardımcı olmak için SQL kurallarında bir kısayol alıyor mu? Belki bir tür ön analiz kullanıyor olabilirsiniz?
  • Yoksa MySQL, tüm RDBMS'leri izlediğimden farklı bir kavramsal yorumlama sırası mı kullanıyor?

1
Benim tahminim, bu senin ikinci kurşun noktan.
a_horse_with_no_name

3
Sanırım sıralama işlevlerini destekleyene kadar herhangi bir belirsizlik veya karışıklığa neden olmaz. Sonra SELECT C, ROW_NUMBER() OVER (ORDER BY X) AS RN FROM T GROUP BY C HAVING RN = 1sıra sorunlu olacak ROW_NUMBERishal sonrasıHAVING
Martin Smith

MySQL tarafından hangi sıralama işlevlerinin desteklendiğinden emin değilim. Eğer satır numarasını isterseniz bu şekilde onu oluşturmak için vardır: SELECT @rownum:=@rownum + 1 as row .... Belki de SELECT takma adlarını desteklemelerinin nedeni, imkansız hale getirecek şeyleri desteklememeleri nedeniyle ... kim bilir? :)
Ohlin

@MartinSmith'in açıkladığı gibi, pencere / sıralama işlevi olmadığı sürece, mantıklı yürütme sırası HAVINGve SELECTdeyimi değiştirilebilir. Yani, bunu yapmakta bir belirsizlik yoktur ve içinde korkunç ifadeler olduğunda kodun görünümünü basitleştirebilir SELECT.
ypercubeᵀᴹ

Umarım bu bir konuyla ilgili bir soruya cevap verdiğimi söylemek için Burada daha hızlı sonuçların tadını çıkarıyor distincts... ile Alias in the Havingaynı Explainçıktıya rağmen . Dolayısıyla Optimizer ile bazı varyasyonlar oluyor.
Drew

Yanıtlar:


13

Peki bu tür bir sorunuz olduğunda IMHO en iyi bilgi kaynağı MySQL belgeleridir. Şimdi konuya gelelim. Bu, GROUP BYvarsayılan olarak etkinleştirilmiş olan MySql uzantısının davranışıdır .

MySQL grup uzantıları
MySQL bu davranışı toplanmış sütun için HAVING yan tümcesinde bir diğer ad kullanımına izin vermek için bu davranışı genişletir

Standart davranış istiyorsanız, bu uzantıyı sql_mode ONLY_FULL_GROUP_BY

SET [SESSION | GLOBAL] sql_mode = ONLY_FULL_GROUP_BY;

Yukarıda belirtilen sorguyu ONLY_FULL_GROUP_BYsql_mode içinde yürütmeye çalışırsanız , aşağıdaki hata iletisini alırsınız:

HAVING yan tümcesinde gruplama dışı 'Tutar' kullanılır: YIL SEÇİN (sipariş tarihi), COUNT (*), YILLARA GÖRE GRUPLARDAN (sipariş tarihi) Tutar> 1

İşte SQLFiddle demosu

Bu nedenle MySQL örneğinizi nasıl yapılandıracağınız ve kullanacağınız size bağlıdır.


Belgeler konusunda kesinlikle haklısınız. Yukarıda alıntıladığınız kadar açık bir şekilde yazılabileceğini hiç düşünmemiştim :) Bulduğunuz için teşekkürler ...
Ohlin

Bu yanıt "MySQL ön analiz yapıyor mu yoksa MySQL farklı bir kavramsal yorum mu kullanıyor?"
Pacerier

2
@Pacerier MySQL elbette "ön analiz yapıyor", çünkü sorgu optimize edici en iyi sorgu planı olduğuna inandığı şeyi seçerken sorgunun tüm yönlerini göz önünde bulunduruyor. "Farklı bir kavramsal yorum" kavramı, sunucunun kavramsal modeli geçerli bir sonuç verecek şekilde uygulamakta özgür olduğu gerçeğinin yanlış anlaşılmasına ihanet eder. ORDER BYÖrneğin, optimize edici satırların başlangıçta istenen sırada olan bir dizinden sırayla okunabileceğini tespit ederse, teorik olarak olduğundan çok daha erken ele alınabilir.
Michael - sqlbot

4

İyi soru.

Bence bu sorguları çalıştırmalısın

EXPLAIN SELECT YEAR(orderdate), COUNT(*) as Amount
FROM Sales.Orders
GROUP BY YEAR(orderdate) 
HAVING Amount>1;
SHOW WARNINGS;

ve sorgunun nasıl yeniden yazıldığını kontrol edin. Sorgu optimize edici Tutarı COUNT (*) ile değiştirdiğinden eminim

SELECT YEAR(orderdate), COUNT(*) as Amount
FROM Sales.Orders
GROUP BY YEAR(orderdate) 
HAVING COUNT(*)>1;

Olduğu gibi

select 
 *
from 
 test
where 
 id = 5 - 3

Sorgu iyileştirici sonra böyle bir şey.

select 
 test.id as 'id'
from 
 test
where 
 test.id = 2
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.