【问题标题】:SQL Query - Display Count & All ID's With Same NameSQL 查询 - 显示计数和所有具有相同名称的 ID
【发布时间】:2012-08-03 17:13:28
【问题描述】:

我正在尝试显示具有相同名称的表条目的数量以及与每个条目关联的唯一 ID。

所以我有一张这样的桌子......

Table Names
------------------------------
ID    Name
0    John
1    Mike
2    John
3    Mike
4    Adam
5    Mike

我希望输出类似于:

Name | Count | IDs
---------------------
Mike     3     1,3,5
John     2     0,2
Adam     1     4

除了显示所有唯一 ID 之外,我有以下查询:

select name, count(*) as ct from names group by name order by ct desc;

【问题讨论】:

  • 您使用的数据库后端的代码有很大的不同,解决方案是特定于客户端的。
  • 又一个原因write once run anywhere SQL 是白日梦! @Mike,您需要指定您需要它的数据库,没有适用于所有数据库的方法。

标签: sql database-design sqlite


【解决方案1】:
select name,
       count(id) as ct, 
       group_concat(id) as IDs
from names
group by name
order by ct desc;

您可以为此使用GROUP_CONCAT

【讨论】:

【解决方案2】:

根据您使用的 MSSQL 版本 (2005+),您可以使用 FOR XML PATH 选项。

SELECT 
    Name, 
    COUNT(*) AS ct, 
    STUFF((SELECT ',' + CAST(ID AS varchar(MAX)) 
           FROM names i 
           WHERE i.Name = n.Name FOR XML PATH(''))
        , 1, 1, '') as IDs
FROM names n
GROUP BY Name
ORDER BY ct DESC

group_concat 最接近的是,除非您使用 SQLCLR 选项(我没有这样做的经验),否则您将使用 MSSQL。 STUFF 函数负责处理前导逗号。此外,您不想为内部 SELECT 加上别名,因为它会将您选择的元素包装在 XML 元素中(TD 的别名会导致每个元素返回为 <TD>value</TD>)。

根据上面的输入,这是我得到的结果:

Name    ct  IDs
Mike    3   1,3,5
John    2   0,2
Adam    1   4

编辑:免责声明

此技术不适用于可能包含特殊字符的字符串字段(例如与符号&、小于<、大于> 以及任何数量的其他格式字符)。因此,这种技术最适用于简单的整数值,尽管如果您绝对确定没有需要转义的特殊字符,仍然可以将其用于文本。因此,请阅读HERE 发布的解决方案,以确保正确转义这些字符。

【讨论】:

  • 您的答案将无法正确处理 XML 字符,例如:<&>。有关在 SQL Server 2005+ 中进行 XML 连接的正确方法,请访问此处:stackoverflow.com/a/5031297/65223
  • 对于简单的 ID(这是他正在寻找的)这很好,尽管我同意你必须小心使用这种技术。
  • @SPFiredrake,对于将来到达此页面并尝试连接特殊字符的可怜人来说,这个答案将是一个巨大的失败。当 OP 尝试重用此方法并开始在其结果集中添加 &> 时,也会发生同样的情况。
  • 添加了免责声明。但是,在这个答案包含修复之前,会有更多流量的答案出现,所以我不太担心它会失败。老实说,我喜欢让我的解决方案尽可能简单,当他们意识到它并不适用于所有情况时,让复制/意大利面军队自己绊倒。见鬼,即使我偶尔也会用这种技术绊倒自己。
【解决方案3】:

这是另一种 SQL Server 方法,使用递归 CTE:

链接到SQLFiddle

; with MyCTE(name,ids, name_id, seq)
as(
    select name, CAST( '' AS VARCHAR(8000) ), -1, 0
    from Data
    group by name
    union all
    select d.name,  
            CAST( ids + CASE WHEN seq = 0 THEN '' ELSE ', ' END + cast(id as varchar) AS VARCHAR(8000) ),
            CAST( id AS int),
            seq + 1
    from MyCTE cte 
    join Data d
        on cte.name = d.name
    where d.id > cte.name_id
)
SELECT name, ids
      FROM ( SELECT name, ids,
                    RANK() OVER ( PARTITION BY name ORDER BY seq DESC )
               FROM MyCTE ) D ( name, ids, rank )
     WHERE rank = 1

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-12-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-29
    • 1970-01-01
    • 2013-10-17
    • 2021-10-27
    相关资源
    最近更新 更多