Как получить записи, где столбец CSV содержит все значения фильтра - PullRequest
0 голосов
/ 23 января 2012

У меня есть таблица, некоторые отделы помечены пользователем как

User   | Department
user1  | IT,HR,House Keeping
user2  | HR,House Keeping
user3  | IT,Finance,HR,Maintainance
user4  | Finance,HR,House Keeping
user5  | IT,HR,Finance

Я создал SP, который принимает параметр varchar (max) в качестве фильтра (я динамически объединяюсь, если в коде C #)

в sp i создала временную таблицу для выбранных фильтров, например; если пользователь выбрал IT & Finance & HR

я слил строку как IT ## Finance ## HR (в C #) и вызвал sp с этим параметром

в SP я создаю временную таблицу как

FilterValue
IT
Finance
HR

теперь вопрос, как я могу получить записи, которые содержат все отделы, связанные с ними (пользователи, связанные со всеми значениями во временной таблице), чтобы получить

User   | Department
user3  | IT,Finance,HR,Maintainance
user5  | IT,HR,Finance

как optput

Пожалуйста, предложите оптимизированный способ достижения этой фильтрации

Ответы [ 2 ]

1 голос
/ 24 января 2012

Я согласен с другими, что ваш дизайн не идеален, и учитывая тот факт, что он может измениться, согласно вашему комментарию, человек не слишком мотивирован, чтобы найти действительно увлекательное решение длятекущая ситуация.

Тем не менее, у вас может быть тот, который, по крайней мере, работает правильно (я думаю) и соответствует ситуации.Вот что я придумал:

;
WITH
  UserDepartment ([User], Department) AS (
    SELECT 'user1', 'IT,HR,House Keeping' UNION ALL
    SELECT 'user2', 'HR,House Keeping' UNION ALL
    SELECT 'user3', 'IT,Finance,HR,Maintainance' UNION ALL
    SELECT 'user4', 'Finance,HR,House Keeping' UNION ALL
    SELECT 'user5', 'IT,HR,Finance'
  ),
  Filter (FilterValue) AS (
    SELECT 'IT' UNION ALL
    SELECT 'Finance' UNION ALL
    SELECT 'HR'
  ),
  CSVSplit AS (
    SELECT
      ud.*,
      --x.node.value('.', 'varchar(max)')
      x.Value AS aDepartment
    FROM UserDepartment ud
    CROSS APPLY (SELECT * FROM dbo.Split(',', ud.Department)) x
  )
SELECT
  c.[User],
  c.Department
FROM CSVSplit c
  INNER JOIN Filter f ON c.aDepartment = f.FilterValue
GROUP BY
  c.[User],
  c.Department
HAVING
  COUNT(*) = (SELECT COUNT(*) FROM Filter)

Первые два CTE - это просто примеры таблиц, остальная часть запроса - это собственно решение.

* CTE CSVSplit используетSplit функция , которая разбивает список через запятую на набор элементов и возвращает их в виде таблицы.Весь CTE превращает набор строк в форме

-----  ---------------------------
user1  department1,department2,...
...    ...

в следующее:

-----  -----------
user1  department1
user1  department2
...    ...

Основной SELECT объединяет нормализованный набор строк с таблицей фильтров и выбирает строки, в которых числосоответствует точно равно количеству элементов в таблице фильтров. (Примечание: это означает, что в UserDepartment.Department нет идентичных имен) .

1 голос
/ 23 января 2012

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

Тем не менее, если вы не в состоянии изменить дизайн, вы можете бездельничатьпроблема с XML, и она может дать вам нормальную производительность.

Попробуйте что-то вроде этого (замените '@test' на имя вашей таблицы, если необходимо ...).Вам даже не нужно будет создавать временную таблицу - это приведет к тому, что строка с разделителями-запятыми переместится в XML, который вы затем можете использовать XQuery напрямую:

DECLARE @test TABLE (usr int, department varchar(1000))

insert into @test (usr, department)
values (1, 'IT,HR,House Keeping')
insert into @test (usr, department)
values (2, 'HR,House Keeping')
insert into @test (usr, department)
values (3, 'IT,Finance,HR,Maintainance')
insert into @test (usr, department)
values (4, 'Finance,HR,House Keeping')
insert into @test (usr, department)
values (5, 'IT,HR,Finance')

;WITH departments (usr, department, depts)
AS
(
    SELECT usr, department, CAST(NULLIF('<department><dept>' + REPLACE(department, ',', '</dept><dept>') + '</dept></department>', '<department><dept></dept></department>') AS xml)
    FROM @test
)
SELECT departments.usr, departments.department
FROM departments
WHERE departments.depts.exist('/department/dept[text()[1] eq "IT"]') = 1
    AND departments.depts.exist('/department/dept[text()[1] eq "HR"]') = 1
    AND departments.depts.exist('/department/dept[text()[1] eq "Finance"]') = 1
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...