【问题标题】:Using an Alias column in the where clause in Postgresql在 Postgresql 的 where 子句中使用别名列
【发布时间】:2011-03-15 13:21:43
【问题描述】:

我有一个这样的查询:

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'

这给出了以下错误:

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

在 MySql 中这是有效的,但在 Postgresql 中显然不是。据我所知,原因是查询的SELECT 部分比WHERE 部分计算得晚。有解决此问题的通用解决方法吗?

【问题讨论】:

  • 这是一个很好的问题,但却是一个奇怪的示例查询。您永远不想为该列选择非 NULL 值,因此整个 CASE 语句是完全没有必要的。
  • @phils 你是对的。查询是动态生成的,因此where 子句可能包含其他内容,但select 部分将保持不变。

标签: sql postgresql column-alias


【解决方案1】:

如您所见,MySQL 的支持是非标准的。正确的方法是重新打印 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

【讨论】:

  • 此外,您可以将 CASE 语句替换为 COALESCE:COALESCE(lead_informations.state, 'NEW') AS lead_state。
  • 不得不重复这样的逻辑似乎有点尴尬,但我想我会这样做。不知道COALESCE - 感谢您的提示。
【解决方案2】:

我相信常见的解决方案是使用内部 SELECT 进行计算(或本例中的 CASE 语句),以便在执行到该查询时,内部 SELECT 的结果可用于整个外部查询。否则,首先评估 WHERE 子句,并且对 SELECT 子句一无所知。

【讨论】:

    【解决方案3】:

    我在同一个问题上苦苦挣扎,“mysql 语法是非标准的”在我看来不是一个有效的论点。 PostgreSQL 还添加了方便的非标准扩展,例如“INSERT ... RETURNING ...”以在插入后获取自动 ID。此外,重复大查询也不是一个优雅的解决方案。

    但是,我发现WITH statement 非常有用(CTE)。它有点在查询中创建一个临时视图,然后您可以像使用普通表一样使用它。我不确定我是否正确地重写了您的 JOIN,但总的来说它应该像这样工作:

    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'
    

    【讨论】:

    • 当您想要跨两种不同的产品做某事时,说某事是“非标准的”是完全正确的。它们都实现了 SQL 标准的一部分,并且都具有非标准扩展。不要指望非标准扩展能够翻译。一定要翻译 SQL 标准部分。话虽如此 - 感谢 WITH 示例。
    • 当标准说一件事,你做其他事情与标准沉默的产品扩展时,也有区别。
    • 这是问题的正确答案。接受的答案有效的唯一原因是因为 WHERE 子句所在的列实际上存在于连接表上,它没有解决查询创建列的别名,例如子查询的别名。
    • 请注意,使用这样的 CTE 与子查询相比,可能会导致行排序略有不同(但总体效果相同),除非您有 order by 子句:)
    【解决方案4】:

    您需要在 where 子句中复制 case 语句,或者我的偏好是执行以下操作:

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

    【讨论】:

      【解决方案5】:

      我在这样的地方使用了别名。 (子查询)。

      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
      

      【讨论】:

      • 你可以说Total > 200,但指定子查询名称可能是一个很好的消歧器:)
      【解决方案6】:

      子查询:

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

      【讨论】:

      • 带有代码的答案通常最好附有说明您发布的内容为何有效以及它如何具体解决问题的说明
      • @C.Nivs 评论不言自明
      • @GianGomen 可能不适合新用户,尤其是如果错过了how to answer 上的指南。它确实可以帮助以后可能遇到此答案的其他人。就像您可能会争辩说,关于如何提出问题的指导方针是不言自明的,但会提出很多不好的问题,因此提供一些有用的建议可以将人们推向正确的方向
      猜你喜欢
      • 1970-01-01
      • 2016-10-28
      • 1970-01-01
      • 2012-01-12
      • 2020-05-14
      • 2010-09-26
      • 1970-01-01
      相关资源
      最近更新 更多