2013-12-11 5 views
1

Мне нужно применить фильтр дат в строках, где OwningOfficeID и ScopeOfficeID не совпадают.Фильтрация строк, если значения двух столбцов не совпадают - sql server

Вот основной запрос;

SELECT distinct v.VisitID, a.OfficeID AS OwningOfficeID, 
     scp.OfficeID AS ScopeOfficeID, V.VisitDate, 
     a.staffID as OwningStaff ,scp.StaffID as OwningScope 
FROM Visits v 
    INNER JOIN VisitDocs vdoc ON vdoc.VisitID = v.VisitID 
    INNER JOIN InspectionScope scp ON scp.ScopeID = v.ScopeID 
    INNER JOIN Assignments a ON a.AssignmentID = scp.AssignmentID 
    INNER JOIN Staff s ON s.StaffID = a.StaffID 
WHERE 
    v.VisitType = 1 AND 
--'SCOPE OWNER AND LOOK FOR INSPECTION REPORT BUT NOT FOR COORD/FINAL REPORT. 
    (scp.StaffID = 141 
     AND EXISTS(SELECT *   
        FROM VisitDocs d   
        WHERE d.VisitID = v.VisitID   
         AND d.docType = 13)   
     AND NOT EXISTS(SELECT * 
         FROM VisitDocs d 
         WHERE d.VisitID = v.VisitID AND d.docType IN (1,2)) 
    ) 
    OR 
--'ASSIGNMENT OWNER AND NOT SCOPE OWNER AND LOOK FOR COORDINATOR REPORT. 
(a.StaffID = 141 AND scp.StaffID != 141 
AND EXISTS(SELECT *   
       FROM VisitDocs d   
       WHERE d.VisitID = v.VisitID   
       AND d.docType = 2)   
AND NOT EXISTS(SELECT * FROM VisitDocs d 
       WHERE d.VisitID = v.VisitID AND d.docType IN (1)) 
) 

Результат Набор

enter image description here

После условие может быть применено к наружному запроса на выборку для достижения результатов.

(OwningOfficeID <> ScopeOfficeID И VisitDate> = '01/11/2012' OR OwningOfficeID = ScopeOfficeID)

Есть в любом случае сделать это в одном операторе отбора?

+0

Не смешивайте AND и OR без явного использования круглых скобок. – lilalinux

+0

Вы можете записать условие более компактно как '((OwningOfficeID = ScopeOfficeID) ИЛИ (VisitDate> = '01/11/2012'))' – LSerni

+0

Я хочу отобразить все строки, где OwningOfficeID = ScopeOfficeID ИЛИ OwningOfficeID <> ScopeOfficeID, но также необходимо применять фильтр даты в тех строках, где OwningOfficeID <> ScopeOfficeID – user1263981

ответ

0

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

Вот как это сделать; использовать CTE. (Если вы не знаете, что такое CTE, прочитайте о них, а затем вернитесь сюда - они задокументированы на веб-сайте Microsoft.)

CTE могут быть намного быстрее и понятнее, чем подзапросы. Позвольте мне показать вам, как, принимая выше код и рефакторингом с КТР я получаю:

WITH DocTypes AS 
(
    SELECT VisitID, docType 
    FROM VisitDocs 
), DocType13 AS 
(
    SELECT VisitID 
    FROM DocTypes 
    WHERE docType = 13 
), DocType1and2 AS 
(
    SELECT VisitID 
    FROM DocTypes 
    WHERE docType IN (1,2) 
), DocType1 AS 
(
    SELECT VisitID 
    FROM DocTypes1and2 
    WHERE docType = 1 
), DocType2 AS 
(
    SELECT VisitID 
    FROM DocTypes1and2 
    WHERE docType = 2 
), Base AS 
(
    SELECT distinct v.VisitID, a.OfficeID AS OwningOfficeID, 
     scp.OfficeID AS ScopeOfficeID, V.VisitDate, 
     a.staffID as OwningStaff ,scp.StaffID as OwningScope 
    FROM Visits v 
     INNER JOIN VisitDocs vdoc ON vdoc.VisitID = v.VisitID 
     INNER JOIN InspectionScope scp ON scp.ScopeID = v.ScopeID 
     INNER JOIN Assignments a ON a.AssignmentID = scp.AssignmentID 
     INNER JOIN Staff s ON s.StaffID = a.StaffID 
    WHERE 
    v.VisitType = 1 AND 
    --'SCOPE OWNER AND LOOK FOR INSPECTION REPORT BUT NOT FOR COORD/FINAL REPORT. 
     (scp.StaffID = 141 
      AND EXISTS(SELECT * FROM DocType13 d WHERE d.VisitID = v.VisitID)   
      AND NOT EXISTS(SELECT * FROM DocType1and2 d WHERE d.VisitID = v.VisitID) 
     ) 
     OR 
    --'ASSIGNMENT OWNER AND NOT SCOPE OWNER AND LOOK FOR COORDINATOR REPORT. 
    (a.StaffID = 141 AND scp.StaffID != 141 
    AND EXISTS(SELECT * FROM DocType2 d WHERE d.VisitID = v.VisitID)   
    AND NOT EXISTS(SELECT * FROM DocType1 d WHERE d.VisitID = v.VisitID) 
) 
) 
SELECT * 
FROM Base 
WHERE (OwningOfficeID <> ScopeOfficeID 
     AND VisitDate >='01/11/2012'( 
     OR OwningOfficeID = ScopeOfficeID 

Должно быть понятно, почему это лучше, но если это не так кратко:

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

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

  • Вы сказали, что хотите применить некоторую логику к этому запросу. Я добавил его в CTE, так как вы можете видеть, что это упрощает «расслоение».

+0

Спасибо за показ метода CTE. Я пробовал это и не вижу большой разницы в производительности. – user1263981

+0

@ user1263981 - производительность имеет много факторов - размер таблиц, индексов и т. Д. - вы не всегда видите волшебство - но вы видите, как добавить дополнительные условия к этому запросу сейчас? – Hogan

+0

не знаю, как поместиться (OwningOfficeID <> ScopeOfficeID AND VisitDate> = '01/11/2012' ИЛИ ​​OwningOfficeID = ScopeOfficeID) с cte – user1263981

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