UNION 与 CTE 一起工作,但不是没有?

UNION works with CTE, but not without?

我正在使用 PostgreSQL 11.12。

我有这个问题:

select first_name, length(first_name)
from db_employee
where length(first_name) = 
(select max(length(first_name)) from db_employee)
order by 1 
limit 1
union
select first_name, length(first_name)
from db_employee
where length(first_name) = 
(select min(length(first_name)) from db_employee)
order by 1 
limit 1

当我 运行 它时,我得到这个错误:

syntax error at or near "union"

如果我使用 CTE,它会起作用:

with cte1 as
(select first_name, length(first_name)
from db_employee
where length(first_name) = 
(select max(length(first_name)) from db_employee)
order by 1 
limit 1),

cte2 as
(select first_name, length(first_name)
from db_employee
where length(first_name) = 
(select min(length(first_name)) from db_employee)
order by 1 
limit 1)

select * from cte1
union
select * from cte2;

为什么第一个查询会导致语法错误?是否可以在不使用 CTE 的情况下让它工作?

要在 UNION 查询中包含每个 SELECTLIMIT 子句,您必须添加 括号 。喜欢:

(  -- !
SELECT first_name, length(first_name)
FROM   db_employee
WHERE  length(first_name) = (SELECT max(length(first_name)) FROM db_employee)
ORDER  BY 1
LIMIT  1
) -- !
UNION
( -- !
SELECT first_name, length(first_name)
FROM   db_employee
WHERE  length(first_name) = (SELECT min(length(first_name)) FROM db_employee)
ORDER  BY 1
LIMIT  1
) -- !

相关:

也就是说,您的查询可以优化。改用:

(
SELECT first_name, length(first_name)
FROM   db_employee
ORDER  BY length(first_name) DESC NULLS LAST, first_name
LIMIT  1
)
UNION ALL  -- my guess
(
SELECT first_name, length(first_name)
FROM   db_employee
ORDER  BY length(first_name), first_name
LIMIT  1
);

细微差别:这不会完全排除具有 first_name IS NULL 的行,但仅当所有行都具有 first_name IS NULL.

时才会显示

关于NULLS LAST

  • Sort by column ASC, but NULL values first?

只需将 sql 部分放在单独的括号中,并在外面保留并集。

    (select first_name, length(first_name)
    from db_employee
    where length(first_name) = 
    (select max(length(first_name)) from db_employee)
    order by 1
    limit 1)
    union
    (select first_name, length(first_name)
    from db_employee
    where length(first_name) = 
    (select min(length(first_name)) from db_employee)
    order by 1
    limit 1);

做同样事情的另一种方法:

    select * from (
    select first_name, l_fname
    ,row_number() over (order by l_fname) rn_min
    ,row_number() over (order by l_fname desc) rn_max
    from(
    select first_name,length(first_name) l_fname from db_employee
    ) A
    ) b where (rn_min = 1 or rn_max = 1);