2016-09-23 119 views
1

我发现这种行为非常奇怪并且违反直觉。 (即使对于SQL)。SQL Server - ROW_NUMBER分区空值的行为

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值替换select查询中的空值之外,是否有任何减轻它的方法?

我本来期望的结果将是

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

使用DENSE_RANK()没有什么区别。

+0

'PARTITION BY'建立群体,所以是不是一致的? “GROUP BY”的功能与SQL:2003标准中记录的相同。 [阅读](https://technet.microsoft.com/en-us/library/ms187007(v = sql.90).aspx) –

+0

阅读它。但是一个小组在组内并没有内在的秩序 - 划分是通过创建这样一个秩序来实现的,因此根本上是不同的 – SimonN

回答

0

呦。

因此,当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