Question

I have a Microsoft SQL Server 2008 database that has a table with multiple entries in one varchar column which are comma separated.

As an example:

----------------------
| Resource_List      |
----------------------
| Danny              |
| Gavin, Danny       |
| Bob, Gavin, Mark   |
| Bob                |
| Bob                |
----------------------

I'm trying to construct a Query that counts the number of times these specific strings existing:

An example of the output I'm after is:

----------------------------------
| Name               |   Count   |
----------------------------------
| Danny              |     2     |
| Gavin              |     2     |
| Mark               |     1     |
| Bob                |     3     |
----------------------------------

The names in the Resource_List are known so I don't mind if I have to specifically add them into the search query. But being able to dynamically determine the names would be more elegant.

So far as the table itself goes - its a third party product that I'm interrogating because the reporting on it is poor, so I don't have the option of normalising the data in the table to a 1:M relationship, outside of what can be dynamically done within a standard query.

Any help in how to construct the query would be appreciated.

Cheers. Courtenay

Was it helpful?

Solution 2

If you have a list of the values in a table, then you can do:

select n.name, count(*)
from table t join
     Names n
     on ','+t.resource_list+',' like '%,'+n.name+',%'
group by n.name;

OTHER TIPS

First, create a string splitting function. Here is one example I re-use quite a bit (see this post for other alternatives):

CREATE FUNCTION [dbo].[SplitStrings]
(
    @List NVARCHAR(MAX),
    @Delim VARCHAR(255)
)
RETURNS TABLE
AS
    RETURN ( SELECT [Value] FROM 
      ( 
        SELECT 
          [Value] = LTRIM(RTRIM(SUBSTRING(@List, [Number],
          CHARINDEX(@Delim, @List + @Delim, [Number]) - [Number])))
        FROM (SELECT Number = ROW_NUMBER() OVER (ORDER BY name)
          FROM sys.all_objects) AS x
          WHERE Number <= LEN(@List)
          AND SUBSTRING(@Delim + @List, [Number], LEN(@Delim)) = @Delim
      ) AS y
    );
GO

Sample usage:

DECLARE @r TABLE(ResourceList NVARCHAR(MAX));

INSERT @r(ResourceList) VALUES(N'Danny'),(N'Gavin, Danny'),
    (N'Bob, Gavin, Mark'),(N'Bob'),(N'Bob');

SELECT s.Value, c = COUNT(*)
FROM @r AS r 
CROSS APPLY dbo.SplitStrings(r.ResourceList, ',') AS s 
GROUP BY s.Value;

Results:

Value   c
-----   --
Gavin   2
Mark    1
Danny   2
Bob     3

Now, if you have a string like Bob, Frank, Bob, Bob will be counted twice, even though it's on the same row. If you only want to count that once, then assuming you have a primary key on the source table, you can do this:

DECLARE @r TABLE(PK INT, ResourceList NVARCHAR(MAX));

INSERT @r VALUES(1,N'Danny'),(2,N'Gavin, Danny'),
    (3,N'Bob, Gavin, Mark'),(4,N'Bob, Frank, Bob');

SELECT s.Value, c = COUNT(DISTINCT r.PK)
FROM @r AS r 
CROSS APPLY dbo.SplitStrings(r.ResourceList, ',') AS s 
GROUP BY s.Value;
GO

Results:

Value   c
-----   --
Bob     2
Danny   2
Frank   1
Gavin   2
Mark    1
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top