SQL: utilizzo dell'alias in Raggruppa per


143

Solo curioso di sintassi SQL. Quindi se ho

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

Questo sarebbe errato perché

GROUP BY itemName, FirstLetter 

dovrebbe davvero essere

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

Ma perché non possiamo semplicemente usare il primo per comodità?


13
questo è permesso in Postgresql
Michael Buen,

7
MySQL lo consente anche
Kip

1
di quale rdbms stai parlando?
Shiwangini,

Risposte:


292

SQL viene implementato come se una query fosse eseguita nel seguente ordine:

  1. Clausola FROM
  2. Dove la clausola
  3. Clausola GROUP BY
  4. Clausola HAVING
  5. Clausola SELECT
  6. Clausola ORDER BY

Per la maggior parte dei sistemi di database relazionali, questo ordine spiega quali nomi (colonne o alias) sono validi perché devono essere stati introdotti in un passaggio precedente.

Pertanto, in Oracle e SQL Server, non è possibile utilizzare un termine nella clausola GROUP BY definito nella clausola SELECT poiché GROUP BY viene eseguito prima della clausola SELECT.

Ci sono comunque delle eccezioni: MySQL e Postgres sembrano avere un'intelligenza aggiuntiva che lo consente.


3
Mi piace questa spiegazione. Anche se non riesco a ipotizzare quanto sia difficile aggiungerlo a un motore come zucchero sintattico.
Haoest

11
Qualche idea se il DB sia abbastanza intelligente da realizzare la stessa espressione è nelle clausole SELECT e GROUP BY senza rivalutare le espressioni? vale a dire se esiste GROUP BY substring(itemName, 1,1), il database è abbastanza intelligente da non subire il colpo alle prestazioni di ricalcolare la sottostringa nella clausola SELECT?
Kip

10
Nella clausola SELECT di una query con raggruppamento, hai accesso solo alle espressioni GROUP BY e ai valori aggregati. Quindi non si tratta di essere intelligenti; deve essere implementato in questo modo affinché il raggruppamento funzioni. (Ed è richiesto dallo standard SQL). Ma anche in casi più banali (ad esempio la stessa espressione nella clausola WHERE e SELECT), i sistemi di database all'avanguardia la calcoleranno sicuramente una sola volta. Questa ottimizzazione è chiamata eliminazione delle sottoespressioni comuni .
Codo

6
Cosa c'entra l'ordine di esecuzione con la domanda? Non è come se il richiedente stesse provando a GROUP BY su COUNT (). In effetti, la query richiesta funziona perfettamente in MySQL e probabilmente PostgreSQL, come sottolineato nei commenti.

1
Per MySQL, sql_modead esclusione ONLY_FULL_GROUP_BY nella maschera di bit, l'ottimizzatore ha la possibilità di fornire risultati migliori con un variato / diverso utilizzo del alias nella HAVINGclausola.
Estratto il

28

È sempre possibile utilizzare una subquery in modo da poter utilizzare l'alias; Naturalmente, controlla le prestazioni (è possibile che il server db funzionerà entrambi allo stesso modo, ma non guasta mai per verificare):

SELECT ItemName, FirstLetter, COUNT(ItemName)
FROM (
    SELECT ItemName, SUBSTRING(ItemName, 1, 1) AS FirstLetter
    FROM table1
    ) ItemNames
GROUP BY ItemName, FirstLetter

2
Le sottoquery dovrebbero essere evitate ove possibile a causa di prestazioni scadenti. L'uso di una copia della funzione è molto meglio perché viene ovviamente rilevato dall'ottimizzatore del database ed eseguito una sola volta.
Roland

1
@Roland ma non c'è differenza nel piano di esecuzione in quel caso. C'è qualche altra considerazione sulle prestazioni?
Guido Mocha,

@Roland, le sottoquery correlate o altre sintassi che portano a cicli o comportamento riga per riga dovrebbero essere evitate, e c'è un limite alla profondità con cui dovresti andare con le sottoquery nidificate, ma generalmente non è vero che le sottoquery conducono a cattive prestazioni. In questo caso, come ha detto Chris, è possibile verificare il piano di esecuzione (piano di query AKA, spiegare il piano) confrontando sia con che senza la subquery, e vedere se c'è davvero qualche differenza. Praticamente ogni motore di database riscriverà la tua query in modo da non avere il totale controllo di ciò che viene eseguito. Questo è il punto della sintassi dichiarativa.
Davos,

16

Almeno in PostgreSQL è possibile utilizzare il numero di colonna nel set di risultati nella clausola GROUP BY:

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

Naturalmente questo inizia a essere un problema se lo stai facendo in modo interattivo e modifichi la query per cambiare il numero o l'ordine delle colonne nel risultato. Ma ancora.


GROUP BY FirstLetterè consentito in Postgresql. Per intenderci, prova a eseguirlo in Postgresql: seleziona sottostringa (table_name, 1,2) come tname dal gruppo information_schema.tables per tname
Michael Buen,

1
@MichaelBuen Mi sembra potenzialmente problematico. Da un test rapido sembra che ci sia un alias e una colonna della tabella di base con lo stesso nome, quest'ultimo ha la priorità? SQL Fiddle . Quindi, se si fa affidamento su questo gruppo per alias, una successiva modifica dello schema potrebbe interrompere in modo silenzioso la query e modificare la semantica.
Martin Smith,

@MartinSmith sapeva solo ora che è un gotcha, si asterrà dall'usarlo, grazie. Dato che PostgreSQL consente tale collegamento, dovrebbero dare priorità all'alias, altrimenti non dovrebbero affatto consentire tale collegamento.
Michael Buen,

Questa è stata una terribile idea dei designer PostgreSQL. È confuso non appena provi GROUP BYqualsiasi espressione che contiene funzioni aggregate o funzioni finestra, che "ovviamente" non funziona.
Lukas Eder,

13

SQL Server non consente di fare riferimento all'alias nella clausola GROUP BY a causa dell'ordine logico di elaborazione. La clausola GROUP BY viene elaborata prima della clausola SELECT, quindi l'alias non è noto quando viene valutata la clausola GROUP BY. Questo spiega anche perché è possibile utilizzare l'alias nella clausola ORDER BY.

Ecco una fonte per informazioni sulle fasi di elaborazione logica di SQL Server .


8

Non sto rispondendo perché è così, ma volevo solo mostrare un modo per aggirare quella limitazione in SQL Server usando CROSS APPLYper creare l'alias. Quindi lo usi nella GROUP BYclausola, in questo modo:

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

4

Si noti che l'utilizzo dell'alias in Group By (per i servizi che lo supportano, come Postgres) può avere risultati non intenzionali. Ad esempio, se si crea un alias già esistente nell'istruzione interna, Raggruppa per sceglierà il nome del campo interno.

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

3

Alcuni DBMS ti permetteranno di usare un alias invece di dover ripetere l'intera espressione.
Teradata ne è un esempio.

Evito la notazione di posizione ordinale come raccomandato da Bill per le ragioni documentate in questa domanda SO .

L'alternativa semplice e affidabile è ripetere sempre l'espressione nella clausola GROUP BY.
DRY NON si applica a SQL.


1

Prestare attenzione all'utilizzo degli alias quando si raggruppano i risultati da una vista in SQLite. Otterrai risultati imprevisti se il nome alias è uguale al nome della colonna di qualsiasi tabella sottostante (alle viste).


0

In passato ho scoperto che Rdb, l'ex prodotto DEC ora supportato da Oracle, consentiva di utilizzare l'alias di colonna in GROUP BY. Il flusso principale Oracle fino alla versione 11 non consente l'utilizzo dell'alias di colonna in GROUP BY. Non sono sicuro di ciò che Postgresql, SQL Server, MySQL, ecc. Consentiranno o meno. YMMV.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.