Sql 有没有办法在程序的WHERE子句中使用条件“IN”语句?

Sql 有没有办法在程序的WHERE子句中使用条件“IN”语句?,sql,tsql,Sql,Tsql,假设我有一个名为Student的表,它有以下列:FirstName、LastName、Grade。现在,让我们假设我有一个名为getStudents的过程,在这个过程中,您可以传递一个逗号分隔的分数列表,从中进行选择。它看起来像这样: CREATE PROCEDURE [dbo].[getStudents] ( @GradeList VARCHAR(MAX) ) AS BEGIN --Declare temporary table for grades CREATE TABL

假设我有一个名为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语句的一部分。我能够通过以下逻辑实现这一点:

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是否有值

我想你想要:

SELECT s.FirstName, s.LastName
FROM Student s
WHERE s.Grade IN (SELECT g.Grade FROM #Grades g) OR
      @GradeList IS NULL;
不需要使用临时表来存储结果。您可以直接在查询中使用split_字符串。但是,如果您确实使用临时表,那么您最好充分利用它。将等级定义为主键:

CREATE TABLE #Grades (
    Grade varchar(50) PRIMARY KEY
);
这提供了更多优化后续查询的机会。

我想您需要:

SELECT s.FirstName, s.LastName
FROM Student s
WHERE s.Grade IN (SELECT g.Grade FROM #Grades g) OR
      @GradeList IS NULL;
不需要使用临时表来存储结果。您可以直接在查询中使用split_字符串。但是,如果您确实使用临时表,那么您最好充分利用它。将等级定义为主键:

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

这为以后的查询提供了更多的优化机会。

不需要使用IF,然后将两个不同的内容加载到temp表中,而是使用IF,然后只执行两个不同的查询,一个带有WHERE和一个不带OUTPUTE,而不是使用IF,然后将两个不同的东西加载到临时表中,一个带有IF,只执行两个不同的查询,一个带有WHERE和一个WITHOUTHOUT选项。与使用两个不同的查询相比,重新编译单个catch all查询可以给出次优的计划。使用OPTION RECOMPILE会有一些额外的编译开销。这就是我需要的答案。我使用的是选项重新编译,正如问题中所述,我需要一个单一的catch-all查询,因为我们希望传入多个可选参数,其中任何组合都可以附加值。如果没有选项重新编译,与两个不同的查询相比,单一的catch-all查询可以给出次优的计划。使用OPTION RECOMPILE会有一些额外的编译开销。这就是我需要的答案。我正在使用optionrecompile,正如问题中所述,我需要一个catch-all查询,因为我们希望传入多个可选参数,其中任何组合都可以附加值。