【问题标题】:DENSE_RANK() - What's wrong here?DENSE_RANK() - 这里有什么问题?
【发布时间】:2021-10-03 10:28:12
【问题描述】:

我有一个非常简单的表格如下:

ID  NAME PRICE
1   A   10.45
2   B   8.25
3   A   10.45
4   C   5.00
5   D   4.00
6   E   10.45

运行DENSE_RANK()

select [name], [price], 
       DENSE_RANK() over (PARTITION BY [name], [price] ORDER BY [name],[price]) as drank
  from temp

我得到以下信息。我希望看到第二行应该有drank 2

name price  drank
A   10.45   1
A   10.45   1  //this should be 2, isn't
B   8.25    1
C   5.00    1
D   4.00    1
E   10.45   1

【问题讨论】:

  • 请解释你要做什么。
  • 如果您在同一列上进行分区和排序,那么您做错了。分区子句是分组,顺序是排序。如果 2 相同,则所述组内的顺序是完全任意的。另外,第二行,NAMEA应该1,你要求DENSE_RANK;排名函数将相等的值赋予相同的排名(请参阅remarks)。好像你想要ROW_NUMBER
  • @Larnu - 你很准。当我将 ORDER BY 更改为 ORDER BY id 时,它给了我想要的东西。看来我对dense_rank() 的理解不正确。你可以发布你的答案吗?
  • 在不知道您所追求的实际结果的情况下,我宁愿不这样做。您只告诉我们第二行是错误的,但其他行呢?如果B 有 2 行价格不同会怎样?如果C 有 3 行,其中 2 行与 price 具有相同的值,而另一行具有不同的值怎么办?

标签: sql sql-server window-functions


【解决方案1】:

这里的问题是您对排名函数的误解。来自DENSE_RANK (Transact-SQL)

备注

如果同一分区中的两行或多行具有相同的排名值,则这些行中的每一行都将获得相同的排名。

RANK 也是如此。这意味着,对于您的数据,nameprice 具有相同的值,因此它们的排名相同;在这种情况下1这两个函数之间的区别在于它们如何处理相等行之后的行。 DENSE_RANK 将针对每个“新”排名按顺序递增,而RANK 将跳过存在相等行的排名。 IE。分别为 1,1,2,3 和 1,1,3,4。

您显然想要的是ROW_NUMBER。但是,我确实注意到,按相同列进行分区和排序通常也是一个缺陷,因为首先对行进行编号是任意的,并且每次的任意编号可能都不相同。理想情况下,您应该按提供明确顺序的另一列进行排序;也许是一个 ID:

SELECT name,
       price,
       ROW_NUMBER() OVER (PARTITION BY name, price ORDER BY SomeOtherColumn) AS RN
FROM dbo.YourTable;

如果您没有要排序的列,则可以使用任意值,甚至可以使用 (SELECT NULL),就像 Gordon 在他们的回答中所做的那样。

【讨论】:

    【解决方案2】:

    如果要枚举具有唯一编号的行,请使用row_number()

    select [name], [price], 
           row_number() over (PARTITION BY [name], [price] ORDER BY (SELECT NULL)) as drank
    from temp;
    

    【讨论】:

    • 谢谢@Gordon。 row_number() 工作。但我真的很想知道为什么dense_rank() 没有做它应该做的事情。我已经去掉了一些不必要的细节。也就是说,我可能需要为每个唯一分区重置该列。
    • 这是一个甜蜜的技术ORDER BY (SELECT NULL)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-01-22
    • 2016-04-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多