Domanda

Ho una domanda come questa:

SELECT t1.id,
    (SELECT COUNT(t2.id)
     FROM t2
     WHERE t2.id = t1.id
          ) as num_things
FROM t1
WHERE num_things = 5;

L'obiettivo è ottenere l'id di tutti gli elementi che compaiono 5 volte nell'altra tabella. Tuttavia, ottengo questo errore:

ERROR: column "num_things" does not exist
SQL state: 42703

Probabilmente sto facendo qualcosa di stupido qui, dato che sono un po 'nuovo nei database. C'è un modo per risolvere questa query in modo che io possa accedere a num_things ? Oppure, in caso contrario, esiste un altro modo per raggiungere questo risultato?

È stato utile?

Soluzione

Penso che potresti semplicemente riscrivere la tua query in questo modo:

SELECT t1.id
FROM t1
WHERE (SELECT COUNT(t2.id)
     FROM t2
     WHERE t2.id = t1.id
          ) = 5;

Altri suggerimenti

Alcuni punti importanti sull'uso di SQL:

  • Non puoi usare gli alias di colonna nella clausola WHERE, ma puoi farlo nella clausola HAVING. Questa è la causa dell'errore che hai.
  • Puoi fare meglio il tuo conteggio usando JOIN e GROUP BY piuttosto che usando subquery correlate. Sarà molto più veloce.
  • Utilizza la clausola HAVING per filtrare i gruppi.

Ecco come scriverei questa query:

SELECT t1.id, COUNT(t2.id) AS num_things
FROM t1 JOIN t2 USING (id)
GROUP BY t1.id
HAVING num_things = 5;

Mi rendo conto che questa query può saltare il JOIN con t1, come nella soluzione di Charles Bretana. Ma suppongo che potresti volere che la query includa alcune altre colonne da t1.


Ri: la domanda nel commento:

La differenza è che la clausola WHERE viene valutata su righe, prima che GROUP BY riduca i gruppi a una singola riga per gruppo. La clausola HAVING viene valutata dopo la formazione dei gruppi. Quindi, ad esempio, non puoi cambiare il COUNT () di un gruppo usando HAVING ; puoi solo escludere il gruppo stesso.

SELECT t1.id, COUNT(t2.id) as num
FROM t1 JOIN t2 USING (id)
WHERE t2.attribute = <value>
GROUP BY t1.id
HAVING num > 5;

Nella query sopra, DOVE filtra per le righe corrispondenti a una condizione e HAVING per i gruppi che hanno almeno cinque conteggi.

Il punto che causa confusione alla maggior parte delle persone è quando non hanno una clausola GROUP BY , quindi sembra come HAVING e < codice> DOVE sono intercambiabili.

DOVE viene valutato prima delle espressioni nell'elenco di selezione. Questo potrebbe non essere ovvio perché la sintassi SQL inserisce prima l'elenco di selezione. Quindi puoi risparmiare molti calcoli costosi usando DOVE per limitare le righe.

SELECT <expensive expressions>
FROM t1
HAVING primaryKey = 1234;

Se si utilizza una query come sopra, le espressioni nell'elenco di selezione vengono calcolate per ogni riga , solo per scartare la maggior parte dei risultati a causa del HAVING condizione. Tuttavia, la query seguente calcola l'espressione solo per la riga singola corrispondente alla condizione WHERE .

SELECT <expensive expressions>
FROM t1
WHERE primaryKey = 1234;

Quindi, per ricapitolare, le query vengono eseguite dal motore di database in base a una serie di passaggi:

  1. Genera un set di righe dalle tabelle, incluse le righe prodotte da JOIN .
  2. Valuta le condizioni DOVE rispetto all'insieme di righe, filtrando le righe che non corrispondono.
  3. Calcola le espressioni nella lista-selezione per ognuna nel set di righe.
  4. Applica gli alias di colonna (nota che questo è un passaggio separato, il che significa che non puoi usare gli alias nelle espressioni nell'elenco select).
  5. Condensare i gruppi in una singola riga per gruppo, in base alla clausola GROUP BY .
  6. Valuta le condizioni HAVING rispetto ai gruppi, filtrando i gruppi che non corrispondono.
  7. Ordina il risultato, secondo la clausola ORDER BY .

Tutti gli altri suggerimenti funzionerebbero, ma per rispondere alla tua domanda di base sarebbe sufficiente scrivere

  SELECT id  From T2
  Group By Id
  Having Count(*) = 5

Vorrei menzionare che in PostgreSQL non è possibile utilizzare la colonna con alias per avere una clausola.

cioè.

SELEZIONA usr_id COME my_id DALL'UTENTE CON my_id = 1

Non funzionerà.

Un altro esempio che non funzionerà:

SELEZIONA su.usr_id COME my_id, COUNT (*) AS val DA sys_user AS su GROUP BY su.usr_id IN VAL > = 1

Ci sarà lo stesso errore: la colonna val non è nota.

Sto evidenziando questo perché Bill Karwin ha scritto qualcosa di non proprio vero per Postgres:

" Non puoi utilizzare gli alias di colonna nella clausola WHERE, ma puoi farlo nella clausola HAVING. Questa è la causa dell'errore che hai. & Quot;

prova questo

SELECT t1.id,
    (SELECT COUNT(t2.id) as myCount
     FROM t2
     WHERE t2.id = t1.id and myCount=5
          ) as num_things
FROM t1
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top