Sql 有没有办法在程序的WHERE子句中使用条件“IN”语句?
假设我有一个名为Student的表,它有以下列:FirstName、LastName、Grade。现在,让我们假设我有一个名为getStudents的过程,在这个过程中,您可以传递一个逗号分隔的分数列表,从中进行选择。它看起来像这样: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
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查询,因为我们希望传入多个可选参数,其中任何组合都可以附加值。