SQL - menggunakan alias di Group By

143

Hanya ingin tahu tentang sintaks SQL. Jadi kalau sudah

SELECT 
 itemName as ItemName,
 substring(itemName, 1,1) as FirstLetter,
 Count(itemName)
FROM table1
GROUP BY itemName, FirstLetter

Ini akan salah karena

GROUP BY itemName, FirstLetter 

memang seharusnya begitu

GROUP BY itemName, substring(itemName, 1,1)

Tapi mengapa kita tidak bisa menggunakan yang pertama untuk kenyamanan?

Terindah
sumber
13
itu diperbolehkan di Postgresql
Michael Buen
7
MySQL memperbolehkannya juga
Kip
1
rdbms mana yang kamu bicarakan?
Shiwangini

Jawaban:

292

SQL diimplementasikan seolah-olah kueri dieksekusi dalam urutan berikut:

  1. DARI klausa
  2. WHERE clause
  3. GROUP BY klausa
  4. MEMILIKI klausa
  5. Klausa SELECT
  6. PESANAN DENGAN klausa

Untuk sebagian besar sistem basis data relasional, urutan ini menjelaskan nama (kolom atau alias) mana yang valid karena mereka harus sudah diperkenalkan pada langkah sebelumnya.

Jadi di Oracle dan SQL Server, Anda tidak bisa menggunakan istilah dalam klausa GROUP BY yang Anda tetapkan dalam klausa SELECT karena GROUP BY dijalankan sebelum klausa SELECT.

Ada beberapa pengecualian: MySQL dan Postgres tampaknya memiliki kecerdasan tambahan yang memungkinkannya.

Codo
sumber
3
Saya suka penjelasan ini. Meskipun saya tidak bisa berspekulasi betapa sulitnya menambahkannya ke mesin sebagai gula sintaksis.
Paling menyenangkan
11
Adakah ide jika DB cukup pintar untuk menyadari ungkapan yang sama ada di klausa SELECT dan GROUP BY tanpa mengevaluasi kembali ekspresi? yaitu jika ada GROUP BY substring(itemName, 1,1), apakah databasenya cukup pintar untuk tidak mengambil kinerja hit mengkompilasi ulang substring dalam klausa SELECT?
Kip
10
Di klausa SELECT dari kueri dengan pengelompokan, Anda hanya memiliki akses ke ekspresi GROUP BY dan nilai-nilai gabungan. Jadi ini bukan tentang menjadi pintar; itu harus dilaksanakan sedemikian rupa agar pengelompokan dapat bekerja. (Dan itu diperlukan oleh standar SQL). Tetapi bahkan dalam kasus-kasus yang lebih sepele (misalnya ungkapan yang sama dalam klausa WHERE dan SELECT), sistem basis data canggih tentu hanya akan menghitungnya sekali. Optimasi ini disebut eliminasi sub-ekspresi umum .
Codo
6
Apa kaitan perintah eksekusi dengan pertanyaan? Ini tidak seperti penanya mencoba MENGELOMPOK DENGAN DENGAN COUNT (). Bahkan, permintaan seperti yang diminta berfungsi dengan baik di MySQL dan kemungkinan PostgreSQL seperti yang ditunjukkan dalam komentar.
1
Untuk mysql, sql_modetidak termasuk ONLY_FULL_GROUP_BY dalam bitmask, Pengoptimal memiliki kesempatan untuk memberikan hasil yang lebih baik dengan beragam / berbeda penggunaan alias dalam HAVINGklausa.
Drew
28

Anda selalu dapat menggunakan subquery sehingga Anda dapat menggunakan alias; Tentu saja, periksa kinerjanya (Kemungkinan server db akan menjalankan keduanya sama, tetapi tidak ada salahnya untuk memverifikasi):

SELECT ItemName, FirstLetter, COUNT(ItemName)
FROM (
    SELECT ItemName, SUBSTRING(ItemName, 1, 1) AS FirstLetter
    FROM table1
    ) ItemNames
GROUP BY ItemName, FirstLetter
Chris Shaffer
sumber
2
Sub-kueri harus dihindari sedapat mungkin karena kinerja yang buruk. Menggunakan salinan fungsi jauh lebih baik karena tentu saja terdeteksi oleh pengoptimal database dan dilakukan hanya sekali.
Roland
1
@Roland tetapi tidak ada yang berbeda dalam rencana eksekusi dalam kasus itu. Apakah ada pertimbangan kinerja lain?
Guido Mocha
@Roland, sub-kueri yang Berkorelasi, atau sintaksis lain yang mengarah pada perilaku loop atau baris-demi-baris harus dihindari, dan ada batas seberapa dalam Anda harus pergi dengan subqueries bersarang, tetapi umumnya tidak benar bahwa sub-kueri mengarah kinerja yang buruk. Dalam hal ini seperti yang dikatakan Chris, Anda dapat memverifikasi rencana eksekusi (rencana kueri AKA, jelaskan rencana) membandingkan keduanya dengan dan tanpa subquery, dan melihat apakah benar-benar ada perbedaan. Hampir setiap mesin basis data akan menulis ulang kueri Anda sehingga Anda tidak sepenuhnya mengendalikan apa yang dijalankan. Itulah inti dari sintaksis deklaratif.
Davos
16

Paling tidak di PostgreSQL Anda bisa menggunakan nomor kolom di resultset di klausa GROUP BY Anda:

SELECT 
 itemName as ItemName,
 substring(itemName, 1,1) as FirstLetter,
 Count(itemName)
FROM table1
GROUP BY 1, 2

Tentu saja ini mulai menyebalkan jika Anda melakukan ini secara interaktif dan Anda mengedit kueri untuk mengubah jumlah atau urutan kolom dalam hasilnya. Tetapi tetap saja.

Bill Gribble
sumber
GROUP BY FirstLetterdiizinkan di Postgresql. Untuk kecerdasan, coba jalankan ini di Postgresql: pilih substring (table_name, 1,2) sebagai tname dari information_schema.tables grup dengan tname
Michael Buen
1
@MichaelBuen Sepertinya berpotensi bermasalah bagi saya. Dari tes cepat sepertinya seolah-olah ada alias dan kolom tabel dasar dengan nama yang sama yang mendapat prioritas? SQL Fiddle . Jadi, jika mengandalkan grup ini dengan perubahan skema yang lain nanti dapat secara diam-diam memecah kueri Anda dan mengubah semantiknya.
Martin Smith
@ MartinSmith hanya tahu sekarang bahwa itu adalah gotcha, akan menahan diri untuk tidak menggunakannya, terima kasih. Mengingat PostgreSQL mengizinkan pintasan itu, mereka harus memberikan prioritas alias, jika tidak, mereka tidak boleh membiarkan pintasan itu sama sekali.
Michael Buen
Ini adalah ide yang mengerikan oleh para perancang PostgreSQL. Ini membingungkan segera setelah Anda mencoba GROUP BYekspresi apa pun yang berisi fungsi agregat atau fungsi jendela, yang "jelas" tidak berfungsi.
Lukas Eder
13

SQL Server tidak memungkinkan Anda untuk merujuk alias dalam klausa GROUP BY karena urutan pemrosesan yang logis. Klausa GROUP BY diproses sebelum klausa SELECT, sehingga alias tidak diketahui saat klausa GROUP BY dievaluasi. Ini juga menjelaskan mengapa Anda dapat menggunakan alias di klausa ORDER BY.

Berikut ini adalah satu sumber untuk informasi tentang fase pemrosesan logis SQL Server .

bobs
sumber
8

Saya tidak menjawab mengapa demikian, tetapi hanya ingin menunjukkan cara mengatasi keterbatasan dalam SQL Server dengan menggunakan CROSS APPLYuntuk membuat alias. Anda kemudian menggunakannya dalam GROUP BYklausa, seperti:

SELECT 
 itemName as ItemName,
 FirstLetter,
 Count(itemName)
FROM table1
CROSS APPLY (SELECT substring(itemName, 1,1) as FirstLetter) Alias
GROUP BY itemName, FirstLetter
Ricardo
sumber
4

Perhatian bahwa menggunakan alias di Group By (untuk layanan yang mendukungnya, seperti postgres) dapat memiliki hasil yang tidak diinginkan. Misalnya, jika Anda membuat alias yang sudah ada di pernyataan bagian dalam, Group By akan memilih nama bidang bagian dalam.

-- Working example in postgres
select col1 as col1_1, avg(col3) as col2_1
from
    (select gender as col1, maritalstatus as col2, 
    yearlyincome as col3 from customer) as layer_1
group by col1_1;

-- Failing example in postgres
select col2 as col1, avg(col3)
from
    (select gender as col1, maritalstatus as col2,
    yearlyincome as col3 from customer) as layer_1
group by col1;
Shannon S
sumber
3

Beberapa DBMS akan membiarkan Anda menggunakan alias alih-alih mengulangi seluruh ekspresi.
Teradata adalah salah satu contohnya.

Saya menghindari notasi posisi ordinal seperti yang direkomendasikan oleh Bill untuk alasan yang didokumentasikan dalam pertanyaan SO ini .

Alternatif yang mudah dan kuat adalah untuk selalu mengulangi ekspresi dalam klausa GROUP BY.
KERING TIDAK berlaku untuk SQL.

mechanical_meat
sumber
1

Hati-hati menggunakan alias saat mengelompokkan hasil dari tampilan dalam SQLite. Anda akan mendapatkan hasil yang tidak terduga jika nama alias sama dengan nama kolom dari tabel yang mendasari (untuk tampilan.)

GGGforce
sumber
0

Kembali pada hari saya menemukan bahwa Rdb, produk DEC sebelumnya sekarang didukung oleh Oracle memungkinkan alias kolom untuk digunakan dalam GROUP BY. Mainstream Oracle melalui versi 11 tidak memungkinkan alias kolom untuk digunakan dalam GROUP BY. Tidak yakin apa yang akan atau tidak akan diizinkan oleh Postgresql, SQL Server, MySQL, dll. YMMV.

Bob Jarvis - Pasang kembali Monica
sumber