【问题标题】:How to select both row_number and count over partition?如何同时选择 row_number 和 count over partition?
【发布时间】:2015-11-20 19:15:55
【问题描述】:

我需要查找重复记录(带有主记录 ID 和重复记录 ID):

select ciid, name from (
select ciid, name, row_number() over (
  partition by related_id, name order by updatedate desc) rn
) where rn = 1;

这给了我主记录 ID,但它也包括没有重复的记录。

如果我使用

select ciid, name from (
select ciid, name, row_number() over (
  partition by related_id, name order by updatedate desc) rn
) where rn > 1;

这会得到所有重复记录,但不是主记录。

我希望我能做这样的事情:

select ciid, name from (
select ciid, name, row_number()  over (
    partition by related_id, name order by updatedate desc
  ) rn, count(*)  over (
    partition by related_id, name order by updatedate desc
  ) cnt
) where rn = 1 and cnt > 1;

但我担心性能,甚至它是否真的在做我想要的。

如何仅获取具有重复项的主记录?请注意,name 不是唯一列。只有ciid 是唯一的。

【问题讨论】:

    标签: sql oracle window-functions


    【解决方案1】:
    select ciid, name 
    from (
    select ciid, name,
    dense_rank() over (partition by related_id, name order by updatedate desc) rn
    from tablename) t
    group by ciid,name
    having count(distinct rn) > 1;
    

    编辑:要查找重复项,为什么不这样做。

    select x.ciid, x.name, x.updatedate
    from tablename x join
    (
    select name, related_id, max(updatedate) as mxdt, count(*)
    from tablename
    group by name, related_id
    having count(*) > 1
    ) t
    on x.updatedate = t.mxdt and x.name = t.name
    

    您可以使用having 执行group by 以仅选择具有多个具有相同行号的行的ID。

    【讨论】:

    • 它什么也不返回...distinct rn 工作吗?似乎分区中每一行的 rn 都不同。
    • 编辑的部分不行吗?只是为了查找重复项?
    • 查找副本很容易..但我需要找到主记录(我将保留的那个),主记录是最新的updatedate
    • 根据评论再次修改。
    • 我意识到这不太可能,但我过去在max() 上遇到的一个问题是可能有两条更新日期相同的记录。我意识到这听起来不太可能,但这是可能的。在这些情况下,row_number() 在保证单个记录方面比max() 更加铁定。我猜max 效率更高,因为它是 O(n)。否则,这是一个非常巧妙的解决方案。
    【解决方案2】:

    我还没有对此进行测试(因为我没有真实数据并且懒得创建一些数据),但似乎这些方面的东西可能会起作用:

    with has_duplicates as (
      select related_id, name
      from yourtable
      group by related_id, name
      having count (*) > 1
    ),
    with_dupes as (
      select
        y.ccid, y.name,
        row_number() over (partition by y.related_id, y.name order by y.updatedate desc) rn
      from
        yourtable y,
        has_duplicates d
      where
        y.related_id = d.related_id and
        y.name = d.name
    )
    select
      ccid, name
    from with_dupes
    where rn = 1
    

    【讨论】:

      【解决方案3】:

      我最终在我的问题中使用了类似的查询:

      select ciid, name from (
      select ciid, name, row_number()  over (
          partition by related_id, name order by updatedate desc
        ) rn, count(*)  over (
          partition by related_id, name desc
        ) cnt
      ) where rn = 1 and cnt > 1;
      

      效果出奇的好。主记录是 rn = 1,重复记录是 rn > 1。确保 count(*) over (partition ..) 不能有 order by 子句。

      【讨论】:

      • 其实这是正确的解决方案。我的解决方案对表执行两次扫描,而您只需一次扫描即可完成此操作。现在我看到它很有意义,我希望我自己想出这个
      • @texasbruce 很棒的答案,不知道你可以使用 count over
      • @texasbruce 这是一个很棒的解决方案,正是我所需要的。谢谢!!
      • +1000 for COUNT(*) OVER - 你总是可以教老 SQL 狗新技巧 :)
      猜你喜欢
      • 2018-07-25
      • 1970-01-01
      • 2018-10-16
      • 2013-02-24
      • 1970-01-01
      • 1970-01-01
      • 2018-04-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多