在 STRING_AGG 中产生 DISTINCT 值

新手上路,请多包涵

我在 SQL Server 2017 中使用 STRING_AGG 函数。我想创建与 COUNT(DISTINCT <column>) 相同的效果。我试过 STRING_AGG(DISTINCT <column>,',') 但这不是合法的语法。

我想知道是否有 T-SQL 解决方法。这是我的示例:

 WITH Sitings
  AS
  (
    SELECT * FROM (VALUES
      (1, 'Florida', 'Orlando', 'bird'),
      (2, 'Florida', 'Orlando', 'dog'),
      (3, 'Arizona', 'Phoenix', 'bird'),
      (4, 'Arizona', 'Phoenix', 'dog'),
      (5, 'Arizona', 'Phoenix', 'bird'),
      (6, 'Arizona', 'Phoenix', 'bird'),
      (7, 'Arizona', 'Phoenix', 'bird'),
      (8, 'Arizona', 'Flagstaff', 'dog')
    ) F (ID, State, City, Siting)
  )
SELECT State, City, COUNT(DISTINCT Siting) [# Of Types], STRING_AGG(Siting,',') Animals
FROM Sitings
GROUP BY State, City

以上产生以下结果:

 +---------+-----------+--------------+-------------------------+
|  State  |   City    | # Of Types   |         Animals         |
+---------+-----------+--------------+-------------------------+
| Arizona | Flagstaff |            1 | dog                     |
| Florida | Orlando   |            2 | dog,bird                |
| Arizona | Phoenix   |            2 | bird,bird,bird,dog,bird |
+---------+-----------+--------------+-------------------------+

输出正是我想要的,除了我希望为亚利桑那州凤凰城列出的串联“动物”是 DISTINCT,如下所示:

 +---------+-----------+--------------+--------------------+
|  State  |   City    | # Of Types   |      Animals       |
+---------+-----------+--------------+--------------------+
| Arizona | Flagstaff |            1 | dog                |
| Florida | Orlando   |            2 | dog,bird           |
| Arizona | Phoenix   |            2 | bird,dog           |
+---------+-----------+--------------+--------------------+

有任何想法吗?

当我使用更大的真实数据集时,我收到关于“动物”列超过 8000 个字符的错误。

我认为我的问题与 问题相同,只是我的示例要简单得多。

原文由 Brent Arias 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 2.9k
2 个回答

这是一种方法。

由于您也需要不同的计数,因此只需将行分组两次即可。第一个 GROUP BY 将删除重复项,第二个 GROUP BY 将产生最终结果。

 WITH
Sitings
AS
(
    SELECT * FROM (VALUES
    (1, 'Florida', 'Orlando', 'bird'),
    (2, 'Florida', 'Orlando', 'dog'),
    (3, 'Arizona', 'Phoenix', 'bird'),
    (4, 'Arizona', 'Phoenix', 'dog'),
    (5, 'Arizona', 'Phoenix', 'bird'),
    (6, 'Arizona', 'Phoenix', 'bird'),
    (7, 'Arizona', 'Phoenix', 'bird'),
    (8, 'Arizona', 'Flagstaff', 'dog')
    ) F (ID, State, City, Siting)
)
,CTE_Animals
AS
(
    SELECT
        State, City, Siting
    FROM Sitings
    GROUP BY State, City, Siting
)
SELECT
    State, City, COUNT(1) AS [# Of Sitings], STRING_AGG(Siting,',') AS Animals
FROM CTE_Animals
GROUP BY State, City
ORDER BY
    State
    ,City
;

结果

+---------+-----------+--------------+----------+
|  State  |   City    | # Of Sitings | Animals  |
+---------+-----------+--------------+----------+
| Arizona | Flagstaff |            1 | dog      |
| Arizona | Phoenix   |            2 | bird,dog |
| Florida | Orlando   |            2 | bird,dog |
+---------+-----------+--------------+----------+


如果您仍然收到有关超过 8000 个字符的错误消息,则在 varchar(max) 之前将值转换为 --- STRING_AGG

就像是

STRING_AGG(CAST(Siting AS varchar(max)),',') AS Animals

原文由 Vladimir Baranov 发布,翻译遵循 CC BY-SA 4.0 许可协议

这是另一种方法( sql fiddle ):

   WITH Sitings
  AS
  (
    SELECT * FROM (VALUES
      (1, 'Florida', 'Orlando', 'bird'),
      (2, 'Florida', 'Orlando', 'dog'),
      (3, 'Arizona', 'Phoenix', 'bird'),
      (4, 'Arizona', 'Phoenix', 'dog'),
      (5, 'Arizona', 'Phoenix', 'bird'),
      (6, 'Arizona', 'Phoenix', 'bird'),
      (7, 'Arizona', 'Phoenix', 'bird'),
      (8, 'Arizona', 'Flagstaff', 'dog')
    ) F (ID, State, City, Siting)
  )

select State,City,count(*) as [# Of Sitings],(select string_agg(value,', ') from (select distinct value from string_split(string_agg(Siting, ','),',')) t) AS Animals
FROM Sitings
GROUP BY State, City

您可以轻松地将拆分和合并部分转换为可重用的标量值函数。

笔记

这不是最佳解决方案,如果您先分组然后进行汇总(如上面的答案),那就更好了。此外,它没有得到 # of Types ,而是得到 # of Sitings 。但是,它作为快速内联函数变得很方便。

原文由 Ravi M Patel 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进