Sql 如何避免重复多次选择和内部联接,并在必要时应用where子句?
在我的存储过程中,我有几个参数,如果其中一个被填充,其中一些参数将被忽略,反之亦然Sql 如何避免重复多次选择和内部联接,并在必要时应用where子句?,sql,sql-server,Sql,Sql Server,在我的存储过程中,我有几个参数,如果其中一个被填充,其中一些参数将被忽略,反之亦然 create procedure FlightReservations @resDate date = getdate, @fromdate date = null, @todate date = null, -- few more parameters as begin
create procedure FlightReservations
@resDate date = getdate,
@fromdate date = null,
@todate date = null,
-- few more parameters
as
begin
if(@fromdate != null)
begin
--it has more inner joins
select * from tbl1 inner join tbl2 on tbl1.id=tbl2.id where tbl1.fromDate=@fromDate
end
else
begin
select * from tbl1 inner join tbl2 on tbl1.id=tbl2.id where tbl1.date=@resDate
end
end
我怎样才能避免重蹈覆辙
select * from tbl1 inner join tbl2 on tbl1.id=tbl2.id
并在结果表上应用where子句?
我需要的是将我的结果设置在类似临时表的东西中,并从临时表中进行选择。但是,既然我不想使用临时表,那么替代方法是什么(因为它包含多个字段,使用临时表不是一个好的选择)一个选择可能是使用动态查询,并根据需要仅构建where子句
DECLARE @sql nvarchar(max) = '<YOUR SELECT & JOIN STATEMENT>'
DECLARE@sql nvarchar(max)=”
然后根据选项构造where子句
if(<CONDITION1>)
BEGIN
SET @sql = @sql + '<WHERE CLAUSE FOR CONDITION1>'
END
if(<CONDITION2>)
BEGIN
SET @sql = @sql + '<WHERE CLAUSE FOR CONDITION2>'
END
...
if()
开始
设置@sql=@sql+''
结束
if()
开始
设置@sql=@sql+''
结束
...
您可以使用此处建议的任何选项执行查询,一个选项可能是使用动态查询并根据需要仅构建where子句
DECLARE @sql nvarchar(max) = '<YOUR SELECT & JOIN STATEMENT>'
DECLARE@sql nvarchar(max)=”
然后根据选项构造where子句
if(<CONDITION1>)
BEGIN
SET @sql = @sql + '<WHERE CLAUSE FOR CONDITION1>'
END
if(<CONDITION2>)
BEGIN
SET @sql = @sql + '<WHERE CLAUSE FOR CONDITION2>'
END
...
if()
开始
设置@sql=@sql+''
结束
if()
开始
设置@sql=@sql+''
结束
...
您可以使用此处建议的任何选项执行查询,请注意,检查null应作为IS null或IS NOT null使用,因为null不是一个值 这应该是你要找的
SELECT * FROM tbl1
INNER JOIN tbl2
ON tbl1.id = tbl2.id
WHERE (@fromdate IS NOT NULL AND tbl1.fromDate = @fromDate)
OR (@fromdate IS NULL AND tbl1.date = @resDate)
注意,对null的检查应该作为IS null或IS NOT null使用,因为null不是一个值 这应该是你要找的
SELECT * FROM tbl1
INNER JOIN tbl2
ON tbl1.id = tbl2.id
WHERE (@fromdate IS NOT NULL AND tbl1.fromDate = @fromDate)
OR (@fromdate IS NULL AND tbl1.date = @resDate)
对于上面演示的案例,您可以使用如下查询
select *
from tbl1 inner join tbl2
on tbl1.id=tbl2.id
where IIF(@fromDate is NULL,tbl1.Date,fromDate)=IIF(@fromDate is NULL,@resDate,@fromDate)
请注意,IIF的两侧条件相同
有关IIF的定义,请参见
请注意,IIF特定于SQL SERVER 2012+对于上面演示的案例,您可以使用如下查询
select *
from tbl1 inner join tbl2
on tbl1.id=tbl2.id
where IIF(@fromDate is NULL,tbl1.Date,fromDate)=IIF(@fromDate is NULL,@resDate,@fromDate)
请注意,IIF的两侧条件相同
有关IIF的定义,请参见
请注意,IIF特定于SQL SERVER 2012+您只希望WHERE子句是有条件的,您可以这样做
-- First option
SELECT * FROM tbl1
INNER JOIN tbl2 ON tbl1.id = tbl2.id
WHERE (@fromdate IS NOT NULL AND tbl1.fromDate = @fromDate)
OR (@fromdate IS NULL AND tbl1.date = @resDate)
-- Another option:
SELECT * FROM tbl1
INNER JOIN tbl2 ON tbl1.id = tbl2.id
WHERE CASE WHEN @fromdate IS NULL THEN tbl1.date = @resDate ELSE tbl1.fromDate = @fromDate END
您只需要WHERE子句是有条件的,您可以这样做
-- First option
SELECT * FROM tbl1
INNER JOIN tbl2 ON tbl1.id = tbl2.id
WHERE (@fromdate IS NOT NULL AND tbl1.fromDate = @fromDate)
OR (@fromdate IS NULL AND tbl1.date = @resDate)
-- Another option:
SELECT * FROM tbl1
INNER JOIN tbl2 ON tbl1.id = tbl2.id
WHERE CASE WHEN @fromdate IS NULL THEN tbl1.date = @resDate ELSE tbl1.fromDate = @fromDate END
使用此方案
(参数为NULL或FieldName=参数)
使用此方案
(参数为NULL或FieldName=参数)
请注意,在这种情况下,重复可能会促进查询优化,而
select
ing all first和filtering later可能是一个障碍。不过,我还没有关于优化的详细知识,所以只是一个想法。“使用临时表不是一个好的选择”-为什么?你应该解释为什么你不想使用它,以避免人们建议任何其他可能遭受相同感知缺点的选项。那么你是说重复整个选择是个好主意吗?我想知道使用临时表是唯一的选项吗?另外,我的结果集几乎有20列,有没有更简单的方法?只选择结果中真正需要的列。请注意,在这种情况下,重复可能会促进查询优化,而select
ing all first和filtering later可能是一个障碍。不过,我还没有关于优化的详细知识,所以只是一个想法。“使用临时表不是一个好的选择”-为什么?你应该解释为什么你不想使用它,以避免人们建议任何其他可能遭受相同感知缺点的选项。那么你是说重复整个选择是个好主意吗?我想知道使用临时表是唯一的选项吗?另外,我的结果集几乎有20列,有没有更简单的方法?只选择结果中真正需要的列。动态查询不是好的选择,因为它会降低代码的可读性。还有其他选择吗?还有,好的,这比字面编码的查询更不适合查询优化人员。动态查询不是一个好的选择,因为它会降低代码的可读性。还有其他选择吗?同样地,这比字面编码的查询更不适合查询优化人员。很好,但正如我说的,我有更多的参数要检查。您会对其余的参数也这样做吗?这是一个不错的选择,但是它使where子句退出变得复杂。对于这个相对简单的where子句来说,这是可行的。如果where子句要复杂得多,则可能需要更复杂的解决方案。除非使用选项(重新编译)
同意,否则执行计划不太可能是最优的。执行计划似乎会随着每种情况而增长。然而,据我所知,他主要比较了时间维度,所以在date和fromdate列上创建索引就足够了。您会对其余的参数也这样做吗?这是一个不错的选择,但是它使where子句退出变得复杂。对于这个相对简单的where子句来说,这是可行的。如果where子句要复杂得多,则可能需要更复杂的解决方案。除非使用选项(重新编译)
同意,否则执行计划不太可能是最优的。执行计划似乎会随着每种情况而增长。然而,据我所知,他主要比较了时间维度,因此在date和fromdate列上创建索引就足够了。应该是或,而不是和。检查原始代码:OP不允许(或说明)两个参数均为null
。应为或,而不是和
。检查原始代码:OP不允许(或说明)两个参数均为null
。