SQL Server - ROW_NUMBER分区的行为按空值

时间:2016-09-23 07:59:23

标签: sql-server null row-number

我发现这种行为非常奇怪且违反直觉。 (即使是SQL)。

set ansi_nulls off
go
;with sampledata(Value, CanBeNull) as
(
  select 1, 1
  union 
  select 2, 2
  union 
  select 3, null
  union 
  select 4, null
  union 
  select 5, null
  union 
  select 6, null
)
select ROW_NUMBER() over(partition by CanBeNull order by      value) 'RowNumber',* from sampledata

返回

1   3   NULL
2   4   NULL
3   5   NULL
4   6   NULL
1   1   1
1   2   2

这意味着为了计算行号,所有空值都被视为同一组的一部分。 SET ANSI_NULLLS是打开还是关闭无关紧要。 但是,根据定义,null是完全未知的,那么如何将空值组合在一起呢?据说,为了按照等级顺序放置东西,苹果和橙子以及负1的平方根和量子黑洞或其他任何东西都可以有意义地排序。一些实验表明,第一列用于生成等级顺序

  select 1, '1'
  union 
  select 2, '2'
  union 
  select 5, null
  union 
  select 6, null
  union
  select 3, null
  union 
  select 4, null

生成相同的值。这会产生重大影响,导致我正在处理的遗留代码出现问题。这是预期的行为吗?除了用唯一值替换select查询中的null之外,还有什么办法可以减轻它吗?

我预期的结果将是

1   3   NULL
1   4   NULL
1   5   NULL
1   6   NULL
1   1   1
1   2   2

使用Dense_Rank()没有任何区别。

1 个答案:

答案 0 :(得分:1)

哟。

因此,当T-SQL处理谓词中的NULL时,它会使用三元逻辑(TRUE,FALSE或UNKNOWN)并显示您在查询中声明的行为。但是,在对值进行分组时,T-SQL将NULL视为一个组。因此,您的查询会将NULL组合在一起并开始对该窗口中的行进行编号。

对于您希望看到的结果,此查询应该有效...

WITH sampledata (Value, CanBeNull)
AS
(
    SELECT 1, 1
    UNION
    SELECT 2, 2
    UNION
    SELECT 3, NULL
    UNION
    SELECT 4, NULL
    UNION
    SELECT 5, NULL
    UNION
    SELECT 6, NULL
)
SELECT
    DENSE_RANK() OVER (PARTITION BY CanBeNull ORDER BY CASE WHEN CanBeNull IS NOT NULL THEN value END ASC) as RowNumber
    ,Value
    ,CanBeNull
FROM sampledata