7

我编写了以下 SQL 语句来从两个表gendata&中获取数据TrainingMatrix

SELECT * FROM (SELECT DISTINCT ON ("TrainingMatrix".payroll, "TrainingName", "Institute")"gendata"."Employee Name","gendata"."Position", "gendata"."Department",  "TrainingMatrix".* 
FROM "TrainingMatrix" JOIN "gendata" ON "TrainingMatrix".payroll = "gendata".payroll 
ORDER  BY payroll, "TrainingName", "Institute" ,"TrainingDate" DESC NULLS LAST) AS foo;

它工作正常,但我需要通过以下方式更多地过滤记录:

WHERE "TrainingMatrix"."ExpiryDate" - current_date <= 0 
AND  EXTRACT(YEAR FROM  "TrainingMatrix"."ExpiryDate") = EXTRACT(YEAR FROM current_date);

因此,原始 SQL 语句将是:

SELECT * FROM (SELECT DISTINCT ON ("TrainingMatrix".payroll, "TrainingName", "Institute")"gendata"."Employee Name","gendata"."Position", "gendata"."Department",  "TrainingMatrix".* 
FROM "TrainingMatrix" JOIN "gendata" ON "TrainingMatrix".payroll = "gendata".payroll 
ORDER  BY payroll, "TrainingName", "Institute" ,"TrainingDate" DESC NULLS LAST) AS foo WHERE "TrainingMatrix"."ExpiryDate" - current_date <= 0 
AND  EXTRACT(YEAR FROM  "TrainingMatrix"."ExpiryDate") = EXTRACT(YEAR FROM current_date);

但我得到了这个错误:

错误:缺少表“TrainingMatrix”第 3 行的 FROM 子句条目:...te","TrainingDate" DESC NULLS LAST) AS foo WHERE "TrainingM...

我正在使用 PostgreSQL。有什么建议吗?

4

2 回答 2

9

100% @a_horse 已经说过了。再加上几件事:

  • 格式化您的查询,以便在您尝试调试之前易于阅读和理解。更重要的是,在您在公共论坛上发帖之前。

  • 使用表别名,尤其是你不幸的 CaMeL 案例名称,以使其更易于阅读。

  • 在查询中提供您的表定义或至少表限定列名,以便我们有机会解析它。您的直接问题已在下面的查询中得到解决。您还将?.相应地替换:

    • t.. 别名"TrainingMatrix"
    • g.. 别名gendata

SELECT *
FROM  (
    SELECT DISTINCT ON (t.payroll, ?."TrainingName", ?."Institute")
           g."Employee Name", g."Position", g."Department",  t.* 
    FROM   "TrainingMatrix" t
    JOIN   gendata          g  ON g.payroll = t.payroll 
    ORDER  BY t.payroll, ?."TrainingName", ?."Institute"
         , ?."TrainingDate" DESC NULLS LAST
    ) AS foo
WHERE  foo."ExpiryDate" - current_date <= 0 
AND    EXTRACT(YEAR FROM  foo."ExpiryDate") = EXTRACT(YEAR FROM current_date);

但还有更多。

  • 就像@a_horse 写的那样,使用必须一直双引号的非法标识符是个坏主意。但是带有封闭空格字符的标识符更糟糕:"Employee Name". 这距离自制 SQL 注入仅一步之遥。

  • 附加过滤器的措辞方式对性能不利

    WHERE  "ExpiryDate" - current_date <= 0 
    

    不可搜索,因此不能使用普通索引。撇开这一点不谈,它也比它需要的要贵。改用:

    WHERE "ExpiryDate" >= current_date
    

    与您的第二个表达式类似,应将其重写为:

    WHERE  "ExpiryDate" >= date_trunc('year', current_date)
    AND    "ExpiryDate"  < date_trunc('year', current_date) + interval '1 year'
    

    结合两者,我们可以去除多余的表达式:

    WHERE  "ExpiryDate" >= current_date
    AND    "ExpiryDate"  < date_trunc('year', current_date) + interval '1 year'
    
  • 你的问题模棱两可。您想在之前DISTINCT还是之后应用附加过滤器?结果不同。
    假设之前 DISTINCT,您不需要子查询 - 这消除了您直接问题的原因:子查询没有不同的别名。

全部一起:

SELECT DISTINCT ON (t.payroll, "TrainingName", "Institute") 
       g."Employee Name", g."Position", g."Department", t.* 
FROM   "TrainingMatrix" t
JOIN   gendata          g USING (payroll)
WHERE  t."ExpiryDate" >= current_date
AND    t."ExpiryDate" <  date_trunc('year', current_date) + interval '1 year'
ORDER  BY t.payroll, "TrainingName", "Institute", "TrainingDate" DESC NULLS LAST
于 2013-11-14T23:34:29.670 回答
6

当您将实际查询包装到派生表 (the select .. from (...) as foo) 中时,您的“表”TrainingMatrix不再被调用。您需要使用用于派生表的别名来引用它:

select *
from (
  ... you original query ..
) as foo
where foo."ExpiryDate" - current_date <= 0
and   extract(year from foo."ExpiryDate") = extract(year from current_date)

顺便说一句:我建议您停止使用"ExpiryDate"区分大小写的名称使用带引号的标识符,这通常会给您带来比其价值更多的麻烦。

于 2013-11-14T11:15:13.783 回答