wake-up-neo.net

Verwenden einer Alias-Spalte in der where-Klausel in Postgresql

Ich habe eine Frage wie diese:

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'

Was gibt den folgenden Fehler:

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

In MySql ist dies gültig, aber offenbar nicht in Postgresql. Der Grund dafür ist, dass der SELECT-Teil der Abfrage später als der WHERE-Teil ausgewertet wird. Gibt es eine allgemeine Problemumgehung für dieses Problem?

51
troelskn

Der Support von MySQL ist, wie Sie erfahren haben, kein Standard. Der korrekte Weg besteht darin, denselben Ausdruck erneut zu drucken, der in der SELECT-Klausel verwendet wird:

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
12
OMG Ponies

Ich hatte Probleme mit dem gleichen Problem und "Mysql-Syntax ist kein Standard" ist meiner Meinung nach kein gültiges Argument. PostgreSQL fügt auch praktische nicht standardmäßige Erweiterungen hinzu, zum Beispiel "INSERT ... RETURNING ...", um Auto-IDs nach Inserts zu erhalten. Das Wiederholen großer Abfragen ist auch keine elegante Lösung.

Ich fand jedoch die WITH-Anweisung sehr hilfreich. Es erstellt sozusagen eine temporäre Ansicht in der Abfrage, die Sie wie eine gewöhnliche Tabelle verwenden können. Ich bin mir nicht sicher, ob ich Ihren JOIN richtig umgeschrieben habe, aber im Allgemeinen sollte es so funktionieren:

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'
53
Marten Lehmann

Sie müssten entweder die case-Anweisung in der where-Klausel duplizieren, oder ich würde es vorziehen, etwas wie das Folgende zu tun:

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')
17
mrSpear

Ich habe Alias ​​in wo verwendet. (Innere Abfrage).

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
0
M Sohail Maroof

Ich glaube, dass die übliche Lösung darin besteht, ein inneres SELECT für die Berechnung (oder in diesem Fall die CASE-Anweisung) zu verwenden, sodass das Ergebnis des inneren SELECT für die gesamte äußere Abfrage verfügbar ist, wenn die Ausführung diese Abfrage abruft. Andernfalls wird die WHERE-Klausel zuerst ausgewertet und weiß nichts über die SELECT-Klausel.

0
David
SELECT "tab_1"."BirthDate", "tab_1"."col_1" FROM (
   SELECT BirthDate, DATEADD(year, 18, BirthDate) AS "col_1" FROM Employees
) AS "tab_1"
WHERE "tab_1"."col_1" >= '2000-12-31';
0
Douglas Rosa