在 STRING_AGG 中生成 DISTINCT 值

问题描述 投票:0回答:5

我在 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 |
+---------+-----------+--------------+-------------------------+

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

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

有什么想法吗?

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

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

sql sql-server distinct sql-server-2017 string-aggregation
5个回答
40
投票

这是一种方法。

由于您还需要不同的计数,因此只需将行分组两次即可完成。第一个

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

16
投票

这是另一种方法(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
。然而,作为快速内联函数,它变得很方便。


13
投票

只需使用

sub-query

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 Types],STRING_AGG(Siting,',') AS Animals from 
    (
      SELECT State, City, Siting
    FROM Sitings 
    GROUP BY State, City,Siting
    ) as T  group by State,City

http://sqlfiddle.com/#!18/ba4b8/11

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

7
投票

您可以在 postgres 中使用它。我不确定mysql。但这在 postgres 中有效。

select state, city, string_agg(distinct (siting), ', ') from sitings group by state, city;

这将仅聚合不同的值。


0
投票

安装CLR函数GROUP_CONCAT: https://github.com/orlando-colamatteo/ms-sql-server-group-concat-sqlclr

然后:

选择 状态, 城市, COUNT(不同的选址) [类型数量], dbo.GROUP_CONCAT(不同的选址)动物 来自地点 按州、城市分组

© www.soinside.com 2019 - 2024. All rights reserved.