SQL условное соединение - PullRequest
1 голос
/ 13 августа 2010

У меня есть три таблицы «Сотрудники», «Отделы» и «Сотрудники». Таблицы «Сотрудники» ссылаются на таблицу «Отделы» (У каждого сотрудника должен быть идентификатор отдела).Однако сотрудник может существовать в нескольких отделах, добавляя записи (EmployeeId и DepartmentId) в таблицу EmployeeInDepartments.

В настоящее время у меня есть следующая хранимая процедура для извлечения сотрудников по отделу:

CREATE PROCEDURE dbo.CollectEmployeesByDepartmentId
    (
    @DepartmentId int,
    @IsDeleted bit
    )
AS
BEGIN
        SELECT   Employees.*
        FROM      Employees 
        WHERE   ((Employees.IsDeleted = @IsDeleted )
            AND ((Employees.DepartmentId = @DepartmentId)
                OR (Employees.EmployeeId IN (SELECT EmployeesInDepartments.EmployeeId
                                        FROM EmployeesInDepartments 
                                        WHERE (EmployeesInDepartments.DepartmentId = @DepartmentId)
                                        )
                    )
                )
        )   
END

Как я могу оптимизировать эту хранимую процедуру и, возможно, использовать JOINS?

Ответы [ 4 ]

4 голосов
/ 13 августа 2010

Вот мой переписать ваш запрос:

WITH summary AS (
   SELECT e.*
     FROM EMPLOYEES e
    WHERE e.isdeleted = @IsDeleted 
      AND e.parentid = 0)
SELECT a.*
  FROM summary a
 WHERE a.departmentid = @DepartmentId
UNION
SELECT b.*
  FROM summary b
  JOIN EMPLOYEESINDEPARTMENTS ed ON ed.employeeid = b.employeeid
                                AND ed.departmentid = @DepartmentId

UNION необходим для удаления дубликатов - если вы знаете, что никогда не будет дубликатов, измените UNION на UNION ALL.

CTE, называемый «сводка», не дает никакого выигрыша в производительности, это просто сокращение.

4 голосов
/ 13 августа 2010

Моя первая рекомендация - удалить идентификатор отдела из таблицы сотрудников.Вставьте все записи сотрудникам в таблицу «Отделы».

Тогда это простое внутреннее объединение.

И, конечно, никогда не используйте select * в рабочем коде.

1 голос
/ 13 августа 2010
   SELECT E.*
   FROM Employees E
      Left Join EmployeesInDepartments EID ON E.EmployeeId = EID.EmployeeId
         And E.DepartmentId <> @DepartmentId 

   WHERE E.IsDeleted = @IsDeleted
      And
      (  
         E.DepartmentId = @DepartmentId 
         Or (EID.DepartmentId = @DepartmentId)
      )

Изменить, чтобы включить логику IsDeleted.Я согласен с некоторыми другими ответами, ваш дизайн, вероятно, следует изменить.Но этот запрос должен сделать это.Если у вас есть дубликаты в EmployeesInDepartments, вы можете изменить это значение на «Выбрать другое».

0 голосов
/ 13 августа 2010

Я бы предложил вам изменить предложение IN, используемое в вашем запросе, на WHERE EXISTS.

Если вы используете IN в своем запросе, это означает, что вы не берете пользу от индексов, определенных в таблице, и запрос выполнит полное сканирование таблицы, что повлияет на производительность запроса.

Вы можете проверить эту тему, чтобы преобразовать IN в WHERE EXISTS:

Изменение IN на EXISTS в SQL

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