SQL Server выбрать, где большинство столбцов совпадают - PullRequest
3 голосов
/ 13 июля 2011

У меня есть хранимая процедура, в которую может быть передано от 1 до 4 переменных, и она должна возвращать строки, в которых совпадает большинство столбцов, или, если нет совпадающих записей, она возвращает значения по умолчанию (которые являются нулевыми).Последовательность должна быть разной.

Пример таблицы с данными:

Client_Id Project_ID Phase Task Employee Sequence
--------- ---------- ----- ---- -------- --------
NULL      NULL       NULL  NULL Chris    1
NULL      NULL       NULL  NULL Bob      100
500       NULL       NULL  NULL Joe      1
500       2          NULL  NULL Max      1

Таким образом, результаты для клиента 100, любого проекта, фазы или задачи будут просто пустыми записями по умолчанию Криса и NULL.Боб.Для Клиента 500 результаты будут Джо и Боб.Для клиента 500 проекта 2 результатом будут Макс и Боб.Сейчас я делаю этот запрос, сначала проверяя задачу, затем соединяя ее с запросом по фазе и проверяя, не перекрываются ли строки, и делаю то же самое для проекта, а затем для клиента.Это кажется невероятно неэффективным, и должен быть разумный путь к этому.Есть мысли?

РЕДАКТИРОВАТЬ - В некоторых примерах запросов я сначала проверяю случай, когда все соответствует

 insert into #TempTracking
    select  p.employee, p.sequence
        from        invoices i, projects p
        where   i.client_id = p.client_id
        and     i.project_no = p.project_no 
        and     i.phase = p.phase 
        and     i.task = p.task

Затем я делаю запросы все менее и менее конкретными и проверяю, что последовательность уже не соответствуетсуществует.

  insert    into #TempTracking
select  p.employee, p.sequence
    from        invoices i, projects p
    where   (i.client_id = p.client_id or i.client_id is null)
    and     (i.project_no = p.project_no or i.project_no is null)
    and     (i.phase = p.phase or i.phase is null) 
    and     (i.task = p.task or i.task is null)
    and     NOT EXISTS ( SELECT * FROM #TempTracking t WHERE t.sequence = p.sequence )

1 Ответ

3 голосов
/ 13 июля 2011

«Совпадение большинства столбцов» очень расплывчато, но я предполагаю, что вы имеете в виду, что если они ищут ноль или если значение в таблице равно нулю, то предположим, что эта запись может быть включена.

Если вам нужна наиболее подходящая строка или все строки, которые ничего не соответствуют, то вам нужно будет сделать что-то вроде этого (оно начинает становиться очень длинным)

DECLARE @Client_Id VARCHAR(MAX) = '500'
DECLARE @Project_ID VARCHAR(MAX) = '2'
DECLARE @Phase VARCHAR(MAX) = NULL
DECLARE @Task VARCHAR(MAX) = NULL

SELECT Employee, Sequence 
FROM 
  (SELECT Employee, Sequence, 
  (
    CASE WHEN (Client_Id = @Client_Id OR Client_Id IS NULL OR @Client_Id IS NULL) THEN 1 ELSE 0 END + 
    CASE WHEN (Project_ID = @Project_ID OR Project_ID IS NULL OR @Project_ID IS NULL) THEN 1 ELSE 0 END + 
    CASE WHEN (Phase = @Phase OR Phase IS NULL OR @Phase IS NULL) THEN 1 ELSE 0 END + 
    CASE WHEN (Task = @Task OR Task IS NULL OR @Task IS NULL) THEN 1 ELSE 0 END
  ) AS MatchCount
WHERE MatchCount = 
  (
    SELECT MAX(
      CASE WHEN (Client_Id = @Client_Id OR Client_Id IS NULL OR @Client_Id IS NULL) THEN 1 ELSE 0 END + 
      CASE WHEN (Project_ID = @Project_ID OR Project_ID IS NULL OR @Project_ID IS NULL) THEN 1 ELSE 0 END + 
      CASE WHEN (Phase = @Phase OR Phase IS NULL OR @Phase IS NULL) THEN 1 ELSE 0 END + 
      CASE WHEN (Task = @Task OR Task IS NULL OR @Task IS NULL) THEN 1 ELSE 0 END
    )
    FROM myTable
  )
  -- Now prevent for duplicate sequence numbers
  AND NOT EXISTS (
    SELECT Employee, Sequence 
    FROM 
      (SELECT Employee, Sequence, 
      (
        CASE WHEN (Client_Id = @Client_Id OR Client_Id IS NULL OR @Client_Id IS NULL) THEN 1 ELSE 0 END + 
        CASE WHEN (Project_ID = @Project_ID OR Project_ID IS NULL OR @Project_ID IS NULL) THEN 1 ELSE 0 END + 
        CASE WHEN (Phase = @Phase OR Phase IS NULL OR @Phase IS NULL) THEN 1 ELSE 0 END + 
        CASE WHEN (Task = @Task OR Task IS NULL OR @Task IS NULL) THEN 1 ELSE 0 END
      ) AS MatchCount
      FROM myTable) mt2
    WHERE mt2.MatchCount = 
      (
        SELECT MAX(
          CASE WHEN (Client_Id = @Client_Id OR Client_Id IS NULL OR @Client_Id IS NULL) THEN 1 ELSE 0 END + 
          CASE WHEN (Project_ID = @Project_ID OR Project_ID IS NULL OR @Project_ID IS NULL) THEN 1 ELSE 0 END + 
          CASE WHEN (Phase = @Phase OR Phase IS NULL OR @Phase IS NULL) THEN 1 ELSE 0 END + 
          CASE WHEN (Task = @Task OR Task IS NULL OR @Task IS NULL) THEN 1 ELSE 0 END
        )
        FROM myTable
      )
      AND mt2.Sequence = myTable.Sequence AND mt2.MatchCount > myTable.MatchCount
  )

Примечание: это вернет все записи в таблице, когда количество совпадающих полей равно нулю.

Я уверен, что это способы, которые можно было бы очистить, чтобы они не были настолько многословными, вставляя все соответствующие строки во временную таблицу и включая количество совпадающих столбцов (MatchCount), уменьшая запрос значительно.

Теперь, так как вы хотите, чтобы уникальные последовательности и строки с наибольшим соответствием были возвращены, искомый результат выглядит примерно так:

DECLARE @Client_Id VARCHAR(MAX) = '500'
DECLARE @Project_ID VARCHAR(MAX) = '3'
DECLARE @Phase VARCHAR(MAX) = NULL
DECLARE @Task VARCHAR(MAX) = NULL

INSERT INTO #myTempTable SELECT Employee, Sequence,
  (
    CASE WHEN (Client_Id = @Client_Id OR Client_Id IS NULL OR @Client_Id IS NULL) THEN 1 ELSE 0 END + 
    CASE WHEN (Project_ID = @Project_ID OR Project_ID IS NULL OR @Project_ID IS NULL) THEN 1 ELSE 0 END + 
    CASE WHEN (Phase = @Phase OR Phase IS NULL OR @Phase IS NULL) THEN 1 ELSE 0 END + 
    CASE WHEN (Task = @Task OR Task IS NULL OR @Task IS NULL) THEN 1 ELSE 0 END
  ) AS MatchCount,
   (
    CASE WHEN (Client_Id IS NULL) THEN 1 ELSE 0 END + 
    CASE WHEN (Project_ID IS NULL) THEN 1 ELSE 0 END + 
    CASE WHEN (Phase IS NULL) THEN 1 ELSE 0 END + 
    CASE WHEN (Task IS NULL) THEN 1 ELSE 0 END
  ) AS NullCount
--   ,(
--    CASE WHEN (Client_Id = @Client_Id OR @Client_Id IS NULL) THEN 1 ELSE 0 END + 
--    CASE WHEN (Project_ID = @Project_ID OR @Project_ID IS NULL) THEN 1 ELSE 0 END + 
--    CASE WHEN (Phase = @Phase OR @Phase IS NULL) THEN 1 ELSE 0 END + 
--    CASE WHEN (Task = @Task OR @Task IS NULL) THEN 1 ELSE 0 END
--  ) AS MatchCountWithoutNulls

SELECT Employee, Sequence
FROM #myTempTable mtt
WHERE MatchCount = (
    SELECT MAX(MatchCount) 
    FROM #myTempTable mtt2 
    WHERE mtt2.Sequence = mtt.Sequence
  )
  AND NullCount = (
    SELECT MIN(NullCount) 
    FROM #myTempTable mtt2 
    WHERE mtt2.Sequence = mtt.Sequence
  )

Или что-то очень близкое к этому, у меня нет тестового стола, поэтому я не могу его пнуть и посмотреть.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...