【问题标题】:Combine GROUP BY and ROW_NUMBER()组合 GROUP BY 和 ROW_NUMBER()
【发布时间】:2015-04-06 23:09:16
【问题描述】:

样本数据

userid         email_address               login_name       name                Title       org            phone_number_com
=============  ==========================  ===============  ==================  ==========  =============  ===================
1192           Steve.Jobs@apple.com        sjobs            Steve Jobs          CEO         Apple          N/A
1274           Steve.Jobs@apple.com        sjobs            Steve Jobs          CFO         Apple          697-4686
1192           Steven.jobs@apple.com       sjobs            Steven jobs         CEO         Apple          604-7126
1885           Bill.Gates@microsoft.com    bgates           Bill Gates          CEO         Microsoft      604-7114
1920           Bill.Gates@microsoft.com    bgates           William Gates       CTR         Microsoft      604-7247
1951           Warren.Buffet@hp.com        wbuffet          Warren Buffet       CEO         HP             614-9141
1954           Warren.Buffet@hp.com        wbuffet          W. Buffet           COO         HP             614-7589
1951           Warren.Buffet@xerox.com     wbuffet          Warren S Buffet     CIO         Xerox          614-8874
1956           Mark.Zuckerberg@fb.com      mzuck            Mark  Zuckerberg    CEO         FB             614-8295

查询

SELECT * 
FROM
    (
        SELECT userid, name, login_name, email_address, phone_number_com,
        ROW_NUMBER() OVER(PARTITION BY [login_name] ORDER BY login_name) Num_Duplicates
        FROM web_user
    ) as Rows
WHERE Num_Duplicates > 1

这是我的第一篇文章,希望我遵循所有程序。我得到一个结果集,其中显示了重复的第二行和第三行。我正在尝试GROUP BY login_name 并且只显示具有最高Num_Duplicates 的行。如果 login_nameNum_Duplicates 为 2 和 3,则仅显示 3 的行。我希望这是有道理的!提前感谢您提供的任何指导。

这些是我希望查询输出的结果:

userid  | email_address | login_name    | name  | Title | org   phone_number_com    | Num_Duplicates       
1192    | Steve.Jobs@apple.com  | sjobs | Steve Jobs    | CEO   | Apple |   N/A | 3      
1885    | Bill.Gates@microsoft.com  | bgates    | Bill Gates    | CEO   | Microsoft | 604-7114  | 2       
1951    | Warren.Buffet@hp.com  | wbuffet   | Warren Buffet | CEO   | HP    | 614-9149  | 3

【问题讨论】:

  • 为什么需要行号?
  • 你会添加你想要的结果吗?
  • 为什么只显示第三个?您正在按 login_name 进行分组和排序,这意味着每个组中的顺序是任意的,并且每次执行时都可能不同。所以1、2、3..它们都是一样的。为什么只显示3?为什么不只显示 2 或只显示 1?
  • 让我们备份并找出您所追求的。您是否只是在列出所有“基于 login_name 的重复项”并显示 3 条记录中的任何一条的字段?
  • 对不起,是的,我毕竟是重复的 login_name,只需要显示任何记录中的一个字段,无论是 2 还是 3。

标签: sql sql-server sql-server-2008


【解决方案1】:

嗯 - 从你的描述听起来你只是想要这样的东西(在我的脑海中):

SELECT login_name, email_address 
FROM web_user
GROUP BY login_name, email_address
HAVING count(*) > 2

【讨论】:

  • 在我的结果中,我需要返回用户 ID、姓名、登录名、电子邮件地址、电话号码_com。
  • 只需根据需要添加 - 例如login_name, email_address, MAX(phone_number),等等。
  • ISE,如果我按我选择的所有列分组,它会给我一个不准确的结果。我只需要对 login_name 进行 GROUP BY 并显示我正在选择的其他字段(例如用户 ID、姓名、登录名、电子邮件地址、电话号码_com)
  • 只要您意识到每组只能有一个其他字段值,即使数据中有更多,您也可以只对一列进行分组,然后选择其余列如上所示,MIN 或 MAX。
【解决方案2】:

如果我理解您要正确执行的操作,您将首先按登录名分组以获取重复次数:

SELECT login_name, COUNT(*) AS num_duplicates
  FROM web_user
 GROUP BY login_name

在这里,您可以使用带有ROW_NUMBER() 的子查询(尽管我建议使用RANK() 以防出现平局),也可以只在窗口函数中使用聚合:

SELECT login_name, COUNT(*) AS num_duplicates
     , RANK() OVER ( ORDER BY COUNT(*) DESC ) AS rn
  FROM web_user
 GROUP BY login_name;

然后将其放入子查询中以仅获取重复次数最多的login_name

SELECT * FROM (
    SELECT login_name, COUNT(*) AS num_duplicates
         , RANK() OVER ( ORDER BY COUNT(*) DESC ) AS rn
      FROM web_user
     GROUP BY login_name
) WHERE rn = 1;

更新每个 OP 的 cmets,问题编辑:

SELECT userid, name, login_name, email_address, phone_number_com, num_duplicates
  FROM (
    SELECT userid, name, login_name, email_address, phone_number_com
         , COUNT(*) OVER ( PARTITION BY login_name ) AS num_duplicates
         , ROW_NUMBER() OVER ( PARTITION BY login_name ORDER BY userid ) AS rn
      FROM web_user
) WHERE num_duplicates > 1 AND rn = 1;

我在上面所做的是使用COUNT(*) 作为窗口函数; login_name 的分区将获得每个登录名的计数。我还按login_name 进行分区以获得ROW_NUMBER() 并按userid 排序,以便我可以返回最小值(您似乎在所需的输出中这样做)。

【讨论】:

  • 我会在那里添加 HAVING COUNT(*) > 2 条件,所以你真的知道这些是重复的
  • 根据 OP 的文字,我很确定这不是 Ariel 想要的。
  • 大卫,我从以下查询开始:
  • SELECT login_name, COUNT(1) AS Num_Duplicates FROM web_user GROUP BY login_name HAVING COUNT(1) > 1 ORDER BY COUNT(1) DESC 我遇到的问题是我需要显示用户 ID、姓名, login_name, email_address, phone_number_com 在结果中。
  • @Ariel,对不起,我真的没有关注你。
【解决方案3】:

以下内容应该可以满足您的需求。

ROW_NUMBER 窗口函数用于识别登录名的第一行。

COUNT 窗口函数用于统计每个 login_name 的行数。

然后,外部查询将结果限制为超过 1 行的 login_name,并且仅返回每个 login_name 的第一行。

DECLARE @users TABLE
(
    userid              int
    , email_address     varchar(100)
    , login_name        varchar(100)
    , name              varchar(100)
    , title             varchar(100)
    , org               varchar(100)
    , phone_number_com  varchar(100)
)

INSERT INTO @users
VALUES
(1192, 'Steve.Jobs@apple.com', 'sjobs', 'Steve Jobs', 'CEO', 'Apple', 'N/A')
, (1274, 'Steve.Jobs@apple.com', 'sjobs', 'Steve Jobs', 'CFO', 'Apple', '697-4686')
, (1192, 'Steven.jobs@apple.com', 'sjobs', 'Steven jobs', 'CEO', 'Apple', '604-7126')
, (1885, 'Bill.Gates@microsoft.com', 'bgates', 'Bill Gates', 'CEO', 'Microsoft', '604-7114')
, (1920, 'Bill.Gates@microsoft.com', 'bgates', 'William Gates', 'CTR', 'Microsoft', '604-7247')
, (1951, 'Warren.Buffet@hp.com', 'wbuffet', 'Warren Buffet', 'CEO', 'HP', '614-9141')
, (1954, 'Warren.Buffet@hp.com', 'wbuffet', 'W. Buffet', 'COO', 'HP', '614-7589')
, (1951, 'Warren.Buffet@xerox.com', 'wbuffet', 'Warren S Buffet', 'CIO', 'Xerox', '614-8874')
, (1956, 'Mark.Zuckerberg@fb.com', 'mzuck', 'Mark Zuckerberg', 'CEO', 'FB', '614-8295')
;

WITH LoginWithWindowFunction AS
(
    SELECT
        *
        , ROW_NUMBER() OVER(PARTITION BY login_name ORDER BY userid) AS LoginOrder
        , COUNT(*) OVER(PARTITION BY login_name) AS Num_Duplicates

    FROM
        @users
)

SELECT
    userid
    , email_address
    , login_name
    , name
    , title
    , org
    , phone_number_com
    , Num_Duplicates

FROM
    LoginWithWindowFunction

WHERE
    LoginOrder = 1
    AND Num_Duplicates > 1

ORDER BY
    userid

【讨论】:

    猜你喜欢
    • 2012-03-25
    • 2011-12-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-19
    相关资源
    最近更新 更多