Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Produce DISTINCT values in STRING_AGG

I'm using the STRING_AGG function in SQL Server 2017. I'd like to create the same effect as COUNT(DISTINCT <column>). I tried STRING_AGG(DISTINCT <column>,',') but that is not legal syntax.

I'd like to know if there is a T-SQL work-around. Here is my sample:

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 

The above produces the following result:

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

The output is exactly what I want, except I want the concatenated "Animals" listed for Phoenix Arizona to be DISTINCT, like this:

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

Any ideas?

When I use my real data set, which is much larger, I get an error about the "Animals" column exceeding 8000 characters.

My question I think is the same as this one, except my example is much simpler.

like image 728
Brent Arias Avatar asked Aug 02 '18 05:08

Brent Arias


People also ask

How can I get distinct values from a table?

The SELECT DISTINCT statement is used to return only distinct (different) values. Inside a table, a column often contains many duplicate values; and sometimes you only want to list the different (distinct) values.

What does STRING_AGG do in SQL?

STRING_AGG is an aggregate function that takes all expressions from rows and concatenates them into a single string. Expression values are implicitly converted to string types and then concatenated. The implicit conversion to strings follows the existing rules for data type conversions.

How do I get distinct comma separated values in SQL?

Solution 1 Available in SQL Server 2016 and later. -- Sort the values: SELECT value FROM STRING_SPLIT(@temp, ',') ORDER BY value; -- Remove duplicates: SELECT DISTINCT value FROM STRING_SPLIT(@temp, ',');


1 Answers

Here is one way to do it.

Since you want the distinct counts as well, it can be done simply by grouping the rows twice. The first GROUP BY will remove duplicates, the second GROUP BY will produce the final result.

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 ; 

Result

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

If you are still getting an error message about exceeding 8000 characters, then cast the values to varchar(max) before STRING_AGG.

Something like

STRING_AGG(CAST(Siting AS varchar(max)),',') AS Animals 
like image 107
Vladimir Baranov Avatar answered Sep 28 '22 03:09

Vladimir Baranov