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;
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
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