2010-07-13 15 views
40

Tengo una consulta como esta:utilizando una columna de alias en la cláusula where en 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' 

que da el siguiente error:

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

en MySQL esto es válido, pero aparentemente no en Postgresql. Por lo que puedo deducir, la razón es que la parte SELECT de la consulta se evalúa más tarde que la parte WHERE. ¿Hay una solución común para este problema?

+0

creo que esto no es válida en PostgreSQL ... – pcent

+1

@pcent que explicaría el error entonces ... – troelskn

+0

Es una buena pregunta, pero una consulta de ejemplo extraña. Nunca desea seleccionar un valor no NULL para esa columna, por lo que toda la declaración CASE es completamente innecesaria. – phils

Respuesta

11

El soporte de MySQL es, como ya lo ha experimentado, no estándar. La forma correcta es volver a imprimir la misma expresión utilizada en la cláusula 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

Además, podría reemplazar la sentencia CASE con COALESCE: 'COALESCE (lead_informations.state, 'NEW') AS lead_state'. –

+3

Parece un poco incómodo tener que duplicar la lógica de esa manera, pero supongo que lo haré luego. No sabía sobre 'COALESCE' - Gracias por ese consejo. – troelskn

0

creo que la solución común es utilizar un SELECT interna para el cálculo (o instrucción CASE en este caso) de manera que el resultado de la inner SELECT está disponible para toda la consulta externa en el momento en que la ejecución llega a esa consulta. De lo contrario, la cláusula WHERE se evalúa primero y no sabe nada sobre la cláusula SELECT.

40

Tuve problemas con el mismo problema y "la sintaxis de mysql no es estándar" no es un argumento válido en mi opinión. PostgreSQL también agrega prácticas extensiones no estándar, por ejemplo, "INSERTAR ... VOLVER ..." para obtener identificadores automáticos después de las inserciones. Además, repetir grandes consultas no es una solución elegante.

Sin embargo, encontré el WITH statement muy útil. De este modo, crea una vista temporal dentro de la consulta que luego puede usar como una tabla habitual. No estoy seguro de si he vuelto a escribir su JOIN correctamente, pero en general debería funcionar así:

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

diciendo que algo es "no estándar" es completamente válido cuando buscas hacer algo en dos productos diferentes. ambos implementan partes de los estándares SQL y ambos tienen extensiones no estándar. no espere que las extensiones no estándar se traduzcan entre ellas. DO espera que las porciones estándar SQL se traduzcan. Dicho eso, gracias por el ejemplo de. – Messy

+1

También hay una diferencia cuando el estándar dice una cosa, y usted hace algo más en comparación con las extensiones del producto donde el estándar es silencioso. –

15

que tendría que o bien duplicar la declaración de caso en la cláusula where, o mi preferencia es hacer algo como el siguiente:

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

He usado alias en donde me gusta esto. (Consulta 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 
Cuestiones relacionadas