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