【问题标题】:SQL Server DISTINCT pagination with ROW_NUMBER() not distinctSQL Server DISTINCT 分页与 ROW_NUMBER() 不不同
【发布时间】:2018-03-21 00:25:45
【问题描述】:

好的,所以基本上我的DISTINCT 使用ROW_NUMBER() 变得无用,我需要避免这种情况,因为它会导致重复的结果(当然除了唯一的数字!)

所以我正在寻找的是一个可以工作但没有重复行的查询,因为 num 是唯一的:

WITH t AS
(
   SELECT DISTINCT *, ROW_NUMBER() OVER (ORDER BY Date) AS num 
   FROM Original_Import 
   LEFT JOIN eqcas.dbo.BASE_PROXY_VIEW_WITHTARGET ON ADName = Targetuser
   WHERE (BaseProxy = 'agmc' OR ADName = 'agmc')
      AND (Commited IS NULL OR Commited = 0)
)
SELECT DISTINCT ID, num, ADName, Description_User, Description_Amex, Amount, Date
FROM t 
WHERE (t.BaseProxy = 'agmc' OR t.ADName = 'agmc') 
   AND num BETWEEN 0 AND 20
   AND (Commited IS NULL OR Commited = 0)
ORDER BY Date

修复它可能相当简单,但鉴于我不是 SQL Server 人员,我不习惯这些内部查询等。

更新:是的,num 用于分页。

【问题讨论】:

  • 关于语法的任何想法,以及它会去哪里?记住我不懂 MSSQL!
  • 见下文并尝试。现在我想我没有完全理解你。您需要以正确的方式对行进行编号,因此您的 CTE 无法按预期工作?
  • BETWEEN 0 AND 20 是静态的,还是用于分页结果?
  • 我能想到的就是在 with T 上执行一个子查询,首先执行 distinct,然后在 distinct 处理后添加行号......我会处理语法,但我'm not near SQL atm...但这似乎会很慢....
  • 缓慢不是问题 :) 这听起来像是正确的解决方案。谁能提供语法?我有 mysql 背景,从不使用内部查询。

标签: sql sql-server pagination distinct


【解决方案1】:

我最近发布的关于ROW_NUMBER() being to SELECT what DENSE_RANK() is to SELECT DISTINCT 的博文似乎晚了两年。您的 CTE 必须替换为:

WITH t AS
(
   SELECT DISTINCT *, DENSE_RANK() OVER (ORDER BY Date, ...) AS num 
   FROM Original_Import 
   LEFT JOIN eqcas.dbo.BASE_PROXY_VIEW_WITHTARGET ON ADName = Targetuser
   WHERE (BaseProxy = 'agmc' OR ADName = 'agmc')
      AND (Commited IS NULL OR Commited = 0)
)
SELECT ...

在上述查询中,DENSE_RANK()ORDER BY 子句需要列出来自Original_ImportBASE_PROXY_VIEW_WITH_TARGET 的所有列,以重现与DISTINCT 关键字相同的顺序。这将为每个重复记录集分配一个等级,这样DISTINCT 将再次起作用。

referenced blog post 中,我还包含了一个指向SQLFiddle 的链接,用一个更简单的例子来说明这一点。

SELECT DISTINCT
  v, 
  DENSE_RANK() OVER (w) row_number
FROM t
WINDOW w AS (ORDER BY v)
ORDER BY v, row_number

An explanation why DISTINCT removes duplicate rows after window functions having been calculated can be found in this post here.

【讨论】:

  • 你可能迟到了两年的答案,但我又迟到了一年,因为它对我有用。非常感谢! ;)
  • 嗨@LukasEder,感谢您的精彩帖子!您如何将COUNT(*) OVER(PARTITION BY 1)DENSE_RANK 结合起来?
  • @epoch:不太清楚你的意思。你想计算不同的记录吗? IE。删除重复项后留下的记录? (这可能最好在一个新的堆栈溢出问题中回答)
  • @LukasEder,感谢卢卡斯的回复,我通过提出一个新问题解决了这个问题:stackoverflow.com/questions/25969508/… :)
  • 晚了几年,但我已将其更改为公认的答案。感谢所有做出贡献的人。从那以后我已经换了好几次雇主了,哈哈。
【解决方案2】:

对此的信心有限,因为我无法测试甚至编译,但这是我所想的一般要点......

WITH t AS
(
   SELECT [insert your fields here], ROW_NUMBER() OVER (ORDER BY Date) AS num 
   FROM (
     SELECT DISTINCT *[insert your fields here]
     FROM Original_Import 
     LEFT JOIN eqcas.dbo.BASE_PROXY_VIEW_WITHTARGET ON ADName = Targetuser
     WHERE (BaseProxy = 'agmc' OR ADName = 'agmc')
      AND (Commited IS NULL OR Commited = 0)) as X
)
SELECT DISTINCT ID, num, ADName, Description_User, Description_Amex, Amount, Date
FROM t 
WHERE (t.BaseProxy = 'agmc' OR t.ADName = 'agmc') 
   AND num BETWEEN 0 AND 20
   AND (Commited IS NULL OR Commited = 0)
ORDER BY Date

【讨论】:

  • 正确。可能有更简单的方法可以做到这一点,但我认为鉴于这种情况,这是最好的答案,原因如下:1.我了解它是如何工作的 2.它工作得很好 3.我有信心它不应该搞砸其他任何事情.
  • 实际上,作为旁注,这里最里面的查询实际上并没有返回一组唯一的结果,但是通过选择我需要的那些(比如查询中的最后一个查询)它起作用了。跨度>
  • @JohnHunt:有点晚了,但DENSE_RANK() 可能是一个合适的选择,在这里
猜你喜欢
  • 2013-08-06
  • 1970-01-01
  • 2013-08-09
  • 1970-01-01
  • 2011-12-10
  • 1970-01-01
  • 2010-09-18
相关资源
最近更新 更多