SQL Server 中的 COALESCE 函数返回 NULL,尽管有一个参数不为 NULL

问题描述 投票:0回答:1

有很多产品提供某种“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 中的一个错误吗?

sql sql-server window-functions coalesce sql-server-2022
1个回答
0
投票

是的,这是一个错误吗?你应该举报。

要解决此问题,请不要在与

COALESCE
子句相同的范围内使用
CASE
/
WINDOW
,不要使用
WINDOW
子句,或使用
ISNULL

© www.soinside.com 2019 - 2024. All rights reserved.