2014-02-04 3 views
1

У меня есть база данных Microsoft SQL Server 2008, в которой есть таблица с несколькими записями в одном столбце varchar, разделенные запятой.SQL Server - укажите количество вхождений для определенных строк в столбце

В качестве примера:

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

Я пытаюсь построить запрос, который подсчитывает, сколько раз эти строки специфичных существующие:

В качестве примера выхода я после:

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

Известны имена в Resource_List, поэтому я не возражаю, если я должен специально добавить их в поисковый запрос. Но возможность динамического определения имен будет более элегантной.

Что касается самой таблицы - ее сторонний продукт, который я допрашиваю, потому что отчетность на нем плохая, поэтому у меня нет возможности нормализовать данные в таблице на 1: M независимо от того, что может быть динамически выполнено в рамках стандартного запроса.

Любая помощь в построении запроса будет оценена по достоинству.

Cheers. Courtenay

+0

Что произойдет, если у вас есть строка в одной строке 'Bob, Frank, Bob'? Делает ли это «Боб» один или два раза? Вы считали, что не заполняете JSON в своей базе данных? –

+0

Как немного больше фона, таблица представляет собой список заданий, а resource_list используется для указания того, какие люди назначены заданию. Приложение, которое находится поверх БД, позволит только каждому добавить человека, поэтому я не верю, что у меня когда-нибудь было бы место, где человек дважды был указан в одном поле. Кроме того, каждое имя уникально, поэтому мы не должны видеть двойных всплесков в одном поле. – Courtenay

+0

Я все еще думаю, что это может быть спроектировано намного лучше, например. почему бы не иметь таблицу, которая уже начинается с «CREATE TABLE dbo.JobResources (JobID, UserID);», которая относится к «Заданиям» и «Пользователям»? Теперь ваша жизнь намного проще для таких запросов, и вам не нужно хранить или анализировать неуправляемые списки, разделенные запятыми. Решение ниже будет работать, но оно очень, очень далекое от оптимального. –

ответ

0

Если у вас есть список значений в таблице, то вы можете сделать:

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

Спасибо, Гордон, ты был совершенно прав. Имена были в другой таблице, и я смог следовать вашему примеру, чтобы обработать запрос, удовлетворяющий моим требованиям. Благодаря! – Courtenay

1

Во-первых, создайте функцию разделения строк. Вот один пример, который я повторно использовать совсем немного (см 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 

Пример:

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; 

Результаты:

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

Теперь, если у вас есть строка, как Bob, Frank, Bob, Bob будет засчитан дважды, даже если он находится в одном ряду. Если вы хотите посчитать, что один раз, то если у вас есть первичный ключ таблицы источника, вы можете сделать это:

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 

Результаты:

Value c 
----- -- 
Bob  2 
Danny 2 
Frank 1 
Gavin 2 
Mark 1 
Смежные вопросы