我编写了以下 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。大家有什么建议吗?
100% @a_horse 已经说过了。另外还有一些事情:
格式化您的查询,以便在尝试调试之前易于人们阅读和理解。更重要的是,在您在公共论坛上发帖之前。
table-qualify列名称,以便我们有机会解析它。您眼前的问题已在下面的查询中得到解决。您还可以相应地替换 ?.
:
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);
但还有更多。
字符的标识符更糟糕:"Employee Name"
。这距离自制 SQL 注入仅一步之遥。
对性能不利。
WHERE "ExpiryDate" - current_date <= 0
不是
sargable,因此不能使用普通索引。撇开这一点不谈,它的成本也比实际需要的要高。代替使用:
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
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"
,使用区分大小写的名称通常会给您带来更多的麻烦。
person
表,然后在其中插入了 2 行,如下所示:
CREATE TABLE person (
id INTEGER,
name VARCHAR(20),
age INTEGER
);
INSERT INTO person (id, first_name, last_name, age)
VALUES (1, 'John', 27), (2, 'David', 32);
然后,尝试使用 SELECT 语句
获取
person
表,省略 FROM
子句会得到相同的错误,如下所示:
postgres=# SELECT person.id, person.name, person.age;
ERROR: missing FROM-clause entry for table "person"
LINE 1: SELECT person.id, person.name, person.age;
但是,我可以得到带有 person
语句和
SELECT
子句的
FROM
表,如下所示:
postgres=# SELECT person.id, person.name, person.age FROM person;
id | name | age
----+-------+-----
1 | John | 27
2 | David | 32
(2 rows)