2010-07-13 3 views
40

Ho una domanda come questa:Utilizzando una colonna alias nella clausola in cui in PostgreSQL

SELECT 
    jobs.*, 
    (
     CASE 
      WHEN lead_informations.state IS NOT NULL THEN lead_informations.state 
      ELSE 'NEW' 
     END 
    ) AS lead_state 
FROM 
    jobs 
    LEFT JOIN lead_informations ON 
     lead_informations.job_id = jobs.id 
     AND 
     lead_informations.mechanic_id = 3 
WHERE 
    lead_state = 'NEW' 

che dà il seguente errore:

PGError: ERROR: column "lead_state" does not exist 
LINE 1: ...s.id AND lead_informations.mechanic_id = 3 WHERE (lead_state... 

In MySql questo è valido, ma a quanto pare non in PostgreSQL. Da quello che posso raccogliere, il motivo è che la parte SELECT della query viene valutata in seguito rispetto alla parte WHERE. C'è una soluzione comune per questo problema?

+0

Credo che questo non è valido per PostgreSQL ... – pcent

+1

@pcent che spiegherebbe l'errore allora ... – troelskn

+0

E 'una buona domanda, ma una query di esempio bizzarro. Non si desidera mai selezionare un valore non NULL per quella colonna, quindi l'intera istruzione CASE non è necessaria. – phils

risposta

11

Il supporto di MySQL è, come da esperienza, non standard. Il modo corretto è quello ristampare la stessa espressione usata nella clausola SELECT:

SELECT 
    jobs.*, 
    CASE 
     WHEN lead_informations.state IS NOT NULL THEN lead_informations.state 
     ELSE 'NEW' 
    END AS lead_state 
FROM 
    jobs 
    LEFT JOIN lead_informations ON 
     lead_informations.job_id = jobs.id 
     AND 
     lead_informations.mechanic_id = 3 
WHERE 
    lead_informations.state IS NULL 
+3

Inoltre, è possibile sostituire la dichiarazione CASE con COALESCE: 'COALESCE (lead_informations.state, 'NEW') AS lead_state'. –

+3

Sembra un po 'imbarazzante dover duplicare la logica in questo modo, ma credo che lo farò solo allora. Non sapevo di 'COALESCE' - Grazie per il suggerimento. – troelskn

0

ritengo la soluzione comune è di usare un SELEZIONA interno per il calcolo (o istruzione CASE in questo caso) in modo che il risultato della SELECT interno è disponibile per l'intera query esterna al momento dell'esecuzione di tale query. In caso contrario, la clausola WHERE viene valutata per prima e non conosce la clausola SELECT.

40

Ho faticato sullo stesso problema e "la sintassi di mysql è non standard" non è un argomento valido secondo me. PostgreSQL aggiunge anche pratici estensioni non standard, ad esempio "INSERIRE ... RITIRO ..." per ottenere gli id ​​automatici dopo gli inserimenti. Inoltre, ripetere query di grandi dimensioni non è una soluzione elegante.

Tuttavia, ho trovato il WITH statement molto utile. Crea una visione temporanea all'interno della query che puoi usare come una normale tabella. Non sono sicuro se ho riscritto vostro ci uniamo in modo corretto, ma in generale dovrebbe funzionare in questo modo:

WITH jobs_refined AS (
    SELECT 
     jobs.*, 
     (SELECT CASE WHEN lead_informations.state IS NOT NULL THEN lead_informations.state ELSE 'NEW' END) AS lead_state 
    FROM jobs 
    LEFT JOIN lead_informations 
     ON lead_informations.job_id = jobs.id 
     AND lead_informations.mechanic_id = 3 
) 
SELECT * 
FROM jobs_refined 
WHERE lead_state = 'NEW' 
+12

dire che qualcosa è "non standard" è completamente valido quando stai cercando di fare qualcosa su due prodotti diversi. entrambi implementano parti dello standard SQL (s) ed entrambi hanno estensioni non standard. non aspettarti che le estensioni non standard traducano in. Si aspettano che le parti standard SQL si traducano. detto questo - grazie per l'esempio WITH. – Messy

+1

C'è anche una differenza quando lo standard dice una cosa, e tu fai qualcos'altro rispetto alle estensioni del prodotto dove lo standard è silenzioso. –

15

si avrebbe bisogno di uno duplicare l'istruzione case nella clausola in cui, o la mia preferenza è di fare qualcosa come la seguente:

SELECT * 
FROM (
SELECT 
    jobs.*, 
    (CASE WHEN lead_informations.state IS NOT NULL THEN lead_informations.state ELSE 'NEW' END) as lead_state 
FROM 
    "jobs" 
    LEFT JOIN lead_informations ON lead_informations.job_id = jobs.id 
    AND lead_informations.mechanic_id = 3 
) q1 
WHERE (lead_state = 'NEW') 
-1

ho usato alias in cui come questo. (Domanda interna).

Select "Vendors"."VendorId", "Vendors"."Name","Result"."Total" 
From (Select "Trans"."VendorId", ("Trans"."A"+"Trans"."B"+"Trans"."C") AS "Total" 
     FROM "Trans" 
    WHERE "Trans"."Year"=2014             
    ) As "Result" 
JOIN "Vendors" ON "Result"."VendorId"="Vendors"."VendorId" 
WHERE "Vendors"."Class"='I' AND "Result"."Total" > 200