2011-07-12 5 views
3

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

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

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, Project 2 результатом будут Макс и Боб. Сейчас я делаю этот запрос, сначала проверяя задачу, а затем присоединяю ее к запросу по фазе и проверяю, не перекрываются ли строки и делают то же самое для проекта, а затем для клиента. Это кажется невероятно неэффективным, и в этом должен быть более умный способ. Есть предположения?

EDIT - Некоторые примеры запросов, я проверяю первый для случая, когда все совпадает

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) 
+0

Какая версия SQL Server? – Matthew

+0

'Для клиента 500, Project 2 результатом будет Макс и Боб.« Не нужно ли просто вернуть Max для этого? –

+0

Абэ поднимает хороший момент, как Боб является действительным результатом для Client 500, Project 2, но Крис нет? – Seph

ответ

3

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

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

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 
) 

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

+0

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

+0

Все в порядке, я думаю, я понимаю, что вы пытаетесь сформулировать ... см. Мое последнее редактирование, и это должно быть то, что вы ищете – Seph

Смежные вопросы