Есть ли способ иметь условное выражение IN в предложении WHERE процедуры? - PullRequest
0 голосов
/ 26 марта 2020

Допустим, у меня есть таблица «Student» со следующими столбцами: FirstName, LastName, Grade. Теперь допустим, что у меня есть процедура getStudents, в которую можно передать список оценок, разделенных запятыми, из которых можно выбирать. Это выглядит примерно так:

CREATE PROCEDURE [dbo].[getStudents] (
@GradeList VARCHAR(MAX)
)
AS
BEGIN
     --Declare temporary table for grades
     CREATE TABLE #Grades (Grade varchar(50))

     --Insert the grades from @GradeList parameter into the temp table
     INSERT INTO
          #Grades
     SELECT value AS Grade
     FROM
          --This is a function that will split the comma delimited list and return the values
          [dbo].[SplitValues] (@GradeList)

     --Select all students that are in the grades provided
     SELECT
          FirstName,
          LastName
     FROM
          Student
     WHERE
          Grade IN (SELECT Grade FROM #Grades)
END

Это все работает как задумано. Но сейчас мы хотим сделать @GradeList необязательным параметром. Если его значение равно NULL, мы хотим вернуть всех студентов. В этом упрощенном примере я бы просто сделал оператор IF, но на самом деле мы хотим иметь несколько необязательных параметров, поэтому он должен быть частью одного и того же оператора SELECT. Я смог заставить это работать со следующими логинами c:

CREATE PROCEDURE [dbo].[getStudents] (
@GradeList VARCHAR(MAX) = NULL
)
AS
BEGIN
     --Declare temporary table for grades
     CREATE TABLE #Grades (Grade varchar(50))

     --Insert list of grades into a temporary table
     IF @GradeList IS NULL
     BEGIN
          --No grades provided, select all possible values for Grade into temp table
          INSERT INTO
               #Grades
          SELECT DISTINCT
               Grade
          FROM
               Student
     END
     ELSE
     BEGIN
          --Insert the grades from @GradeList parameter into the temp table
          INSERT INTO
               #Grades
          SELECT value AS Grade
          FROM
               --This is a function that will split the comma delimited list and return the values
               [dbo].[SplitValues] (@GradeList)
     END

     --Select all students that are in the grades provided
     SELECT
          FirstName,
          LastName
     FROM
          Student
     WHERE
          Grade IN (SELECT Grade FROM #Grades)
END

Так что, если ничего не передается, я просто добавляю все возможные значения Grade во временную таблицу #Grades. Функционально это работает и делает то, что мы хотим. Однако, поскольку здесь мы имеем дело с большими таблицами, это добавило огромные накладные расходы к процедуре (теперь она занимает до минуты, прежде чем это было ~ 1-2 секунды). Есть ли способ, чтобы условие в предложении WHERE зависело от того, существует ли значение для @GradeList?

1 Ответ

2 голосов
/ 26 марта 2020

Я думаю, что вы хотите:

SELECT s.FirstName, s.LastName
FROM Student s
WHERE s.Grade IN (SELECT g.Grade FROM #Grades g) OR
      @GradeList IS NULL;

Нет необходимости использовать временную таблицу для хранения результатов. Вы можете просто использовать split_string() непосредственно в запросе. Однако, если вы используете временную таблицу, вы можете использовать ее наилучшим образом. Определите Grade как первичный ключ:

CREATE TABLE #Grades (
    Grade varchar(50) PRIMARY KEY
);

Это дает больше возможностей для оптимизации последующего запроса.

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