有很多产品提供某种“SQL Server”,但只有 Microsoft 的一种产品,因此我将其称为“MS SQL”,特别是当它涉及到它的语言时。
我有一份在不同部门工作的员工名单。
create table emp
(
emp_name varchar(15) primary key,
birthdate date not null,
dept_id integer not null
);
insert into emp
values ('Erna', '1969-01-17', 1),
('Peter', '1970-02-13', 1),
('Urs', '1998-11-07', 1),
('Ulli', '1969-04-15', 1),
('Andreas', '2004-06-23', 2),
('Vera', '1995-12-02', 2),
('Herta', '2006-03-03', 3),
('Django', '1997-10-09', 3);
现在我想要一个按照每年生日顺序排列的列表,包括以下下一个过生日的人。由于当年最后一个人没有继任者,所以应该任命第一个人。所有这些都按部门进行。
with cte1 as
(
select
emp_name, dept_id, birthdate,
count(*) over abt as anz_in_abt,
coalesce(lead(emp_name) over abt,
first_value(emp_name) over abt) as ausr,
coalesce(lead(birthdate) over abt,
first_value(birthdate) over abt) as bd_ausr
from
emp
window abt as (
partition by dept_id
order by month(birthdate), day(birthdate)
-- rows between unbounded preceding and unbounded following
)
)
select *
from cte1
order by dept_id, month(birthdate), day(birthdate);
SQL Server 不喜欢“rows Between”子句,所以我将其注释掉。在 PostgreSQL 和 SQLite 中,不管有没有这个子句,它都可以工作,但 SQL Server 不会将前两个部门的第一个人显示为当年最后一个人的继任者,而是显示
NULL
值。
emp_name|dept_id|birthdate |anz_in_abt|ausr |bd_ausr |
--------+-------+----------+----------+------+----------+
Erna | 1|1969-01-17| 1|Peter |1970-02-13|
Peter | 1|1970-02-13| 2|Ulli |1969-04-15|
Ulli | 1|1969-04-15| 3|Urs |1998-11-07|
Urs | 1|1998-11-07| 4| | |
Andreas | 2|2004-06-23| 1|Vera |1995-12-02|
Vera | 2|1995-12-02| 2| | |
Herta | 3|2006-03-03| 1|Django|1997-10-09|
Django | 3|1997-10-09| 2|Herta |2006-03-03|
由于 PostgreSQL 中从日期中提取日和月的语法不同,我添加了两个函数来使 SQL Server 的代码正常工作。
create or replace function month(d date) returns smallint
begin atomic
select extract(month from d);
end;
create or replace function year(d date) returns smallint
begin atomic
select extract(year from d);
end;
SQLite 使用 strftime() 提取日期和月份,因此代码不完全相同。
with cte1 as (
select emp_name, dept_id, birthdate, count(*) over abt as anz_in_abt,
coalesce(lead(emp_name) over abt, first_value(emp_name) over abt) as ausr,
coalesce(lead(birthdate) over abt, first_value(birthdate) over abt) as bd_ausr
from emp
window abt as (
partition by dept_id
order by strftime('%m', birthdate), strftime('%d', birthdate)
rows between unbounded preceding and unbounded following
)
)
select *
from cte1
order by dept_id, strftime('%m', birthdate), strftime('%d', birthdate);
PostgreSQL和SQLite给出的正确结果是
emp_name | dept_id | birthdate | anz_in_abt | ausr | bd_ausr
----------+---------+------------+------------+---------+------------
Erna | 1 | 1969-01-17 | 1 | Peter | 1970-02-13
Peter | 1 | 1970-02-13 | 2 | Ulli | 1969-04-15
Ulli | 1 | 1969-04-15 | 3 | Urs | 1998-11-07
Urs | 1 | 1998-11-07 | 4 | Erna | 1969-01-17
Andreas | 2 | 2004-06-23 | 1 | Vera | 1995-12-02
Vera | 2 | 1995-12-02 | 2 | Andreas | 2004-06-23
Herta | 3 | 2006-03-03 | 1 | Django | 1997-10-09
Django | 3 | 1997-10-09 | 2 | Herta | 2006-03-03
那么,这是 SQL Server 2022 中的一个错误吗?
是的,这是一个错误吗?你应该举报。
要解决此问题,请不要在与
COALESCE
子句相同的范围内使用 CASE
/WINDOW
,不要使用 WINDOW
子句,或使用 ISNULL
。