【问题标题】:Select Single Record if ID/Name is Duplicated如果 ID/名称重复,请选择单个记录
【发布时间】:2012-11-10 04:01:12
【问题描述】:

这似乎是一个非常简单的问题,但我现在似乎无法弄清楚......

这是我从当前存储过程中获取的数据的简化视图:

ID     Name         Class     Desc
---    -----        ------    -----
84     Calvin J.    2B
53     Fred D.      3B
53     Fred D.      ADJ       Change/Correction
47     Mary F.      3A
47     Mary F.      ADJ       New Product
09     Donald M.    ADJ       Cancelled
21     Richard G.   ADJ       Bad Debt
21     Richard G.   ADJ       Cancelled

我需要修改我的程序,以便每个人只选择一条记录。如果一个人有调整,我只想选择有调整的记录,而忽略其他记录。基于以上,这是我试图返回的结果集:

ID     Name         Class     Desc
---    -----        ------    -----
84     Calvin J.    2B
53     Fred D.      ADJ       Change/Correction
47     Mary F.      ADJ       New Product
09     Donald M.    ADJ       Cancelled
21     Richard G.   ADJ       Cancelled

请帮忙!

更新

我刚刚意识到这个查询还有一个额外的要求;如果有两项调整,一项描述为“坏账”,另一项描述为“已取消”,则需要选择描述为“已取消”的记录(参见上面的更新数据)。

【问题讨论】:

    标签: tsql select duplicates


    【解决方案1】:

    这应该可以解决问题:

    SELECT ID, Name, Class, [Desc]
    FROM (
      SELECT ID, Name, Class, [Desc],
             ROW_NUMBER() OVER(PARTITION BY ID
                               ORDER BY CASE WHEN Class = 'ADJ'
                                             THEN 0 ELSE 1 END) rn
      FROM Table1
    ) A
    WHERE rn = 1
    

    它看起来比实际更可怕。内部查询包含一个使用ROW_NUMBER() 计算的额外列。这样做的目的是对您的行进行编号,每个不同的 ID(在 PARTITION BY 中指定)从 1 开始。 ORDER BY 告诉 ROW_NUMBER() 如何对行进行排序,它是一个 case 语句,表示带有 Class = 'ADJ' 的行应该位于所有其他行之前。然后最后我们只抓取编号为 1 的行。结果是选择 ADJ 行,如果有对应 ID 的行,否则选择常规行。

    根据更新后的要求进行编辑
    如果您有其他优先级标准,则可以将它们添加到 ORDER BY,就像在常规查询中添加 ORDER BY 一样。通常只执行内部查询而不过滤到rn = 1 会很有帮助,这样您就可以准确地看到行号是如何分配的。

    这是应该满足您的新要求的更新查询:

    SELECT ID, Name, Class, [Desc]
    FROM (
      SELECT ID, Name, Class, [Desc],
             ROW_NUMBER() OVER(PARTITION BY ID
                               ORDER BY
                                 CASE WHEN Class = 'ADJ'
                                      THEN 0 ELSE 1 END,
                                 CASE WHEN [Desc] = 'Cancelled'
                                      THEN 0 ELSE 1 END) rn
      FROM Table1
    ) A
    WHERE rn = 1
    

    See it in action here.

    【讨论】:

    • 您好乍得,感谢您的回复。但这对我来说仍然没有意义。如果我为 class= 'ADJ' 的行指定 rn 为 0 并在 where 子句中选择 rn = 1,我将永远不会在我的结果集中看到它们,因为正如你所说,“我们只抓取编号为 1 的行"。
    • 好问题 - 0 或 1 实际上不是 rn。 ROW_NUMBER() 每个 ID 从 1 开始,计数为 2、3、4 等。0 或 1 告诉 ROW_NUMBER() 如何对行进行排序,例如如果有 ADJ 行,那么它将出现在没有 ADJ 的行之前,因此编号为 1。
    • 乍得,根据你给出的解释,你的解决方案应该可以工作,但不幸的是我仍然没有得到想要的记录。
    猜你喜欢
    • 2022-01-21
    • 1970-01-01
    • 1970-01-01
    • 2011-08-05
    • 1970-01-01
    • 2017-03-24
    • 2021-03-16
    • 2013-12-29
    • 1970-01-01
    相关资源
    最近更新 更多