我得到了一个SQL语句,它使用一些参数来过滤输出。
看起来像这样:
ALTER PROCEDURE [dbo].[spGetPerson]
@Vorname varchar(50),
@Nachname varchar(50),
@FirmaID int,
@AbteilungID int,
@ArbeitsortID int,
@FunktionID int
AS
BEGIN
SET NOCOUNT ON;
-- Insert statements for procedure here
Select
p.Vorname, p.Nachname, ar.Arbeitsort, fi.Firma,
ab.Abteilung, fu.Funktion
From
tblPerson p
inner join
tblArbeitsort ar on ar.ArbeitsortID = p.Arbeitsort_fk
inner join
tblFirmaHatAbteilungUndPersonHatFunktion zt on zt.Person_fk = p.PersonID
inner join
tblFirma fi on fi.FirmaID = zt.Firma_fk
inner join
tblAbteilung ab on ab.AbteilungID = zt.Abteilung_fk
inner join
tblFunktion fu on fu.FunktionID = zt.Funktion_fk
Where
p.Vorname = @Vorname
AND p.Nachname = @Nachname
AND fi.FirmaID = @FirmaID
AND ab.AbteilungID = @AbteilungID
AND ar.ArbeitsortID = @ArbeitsortID
AND fu.FunktionID = @FunktionID
END
我正在加入一些东西,但这并不重要。
正如您在最后看到的那样,我使用了WHERE
子句中的每个参数。我想做的是,如果缺少一个参数,相关的“where”就会消失。
作为示例如果缺少@Nachname
,则语句应如下所示:
Where
p.Vorname = @Vorname
AND fi.FirmaID = @FirmaID
AND ab.AbteilungID = @AbteilungID
AND ar.ArbeitsortID = @ArbeitsortID
AND fu.FunktionID = @FunktionID
我该怎么做?
答案 0 :(得分:3)
我发现在这些案件中救援的另一种方式如下。它的工作原理很简单。如果required参数不为null,则将使用其他列与自身匹配,从而导致引擎忽略该连接,因为WHERE 1 = 1类型连接被跳过。希望这有帮助
Where
p.Vorname = COALESCE(@Vorname, p.Vorname)
AND fi.FirmaID = COALESCE(@FirmaID ,fi.FirmaID )
AND ab.AbteilungID = COALESCE(@AbteilungID ,ab.AbteilungID )
AND ar.ArbeitsortID = COALESCE(@ArbeitsortID,ar.ArbeitsortID )
AND fu.FunktionID = COALESCE(@FunktionID,fu.FunktionID)
答案 1 :(得分:2)
执行此操作的典型方法是使用如下逻辑:
Where (p.Vorname = @Vorname or @Vorname is null) AND
(p.Nachname = @Nachname or @Nachname is null) AND
(fi.FirmaID = @FirmaID or @FirmaID is null) AND
(ab.AbteilungID = @AbteilungID or @AbteilungID is null) AND
(ar.ArbeitsortID = @ArbeitsortID or @ArbeitsortID is null) AND
(fu.FunktionID = @FunktionID or @FunktionID is null)
一个注意事项:使用此类复杂的where
子句会影响查询的优化策略。如果性能是一个大问题(并且您在用于条件的where
子句中的列上有索引),那么您可能希望使用动态SQL。也就是说,您将根据具有值的参数构造where
子句,而不是在运行时检查NULL
。
答案 2 :(得分:2)
根据您的表格大小(记录数量)以及填充过滤器的方式(可能您大部分时间只指定了两个过滤器,dynamic SQL
可能会带来更好的结果):
DECLARE @SQL NVARCHAR(MAX) = N'
Select p.Vorname, p.Nachname, ar.Arbeitsort, fi.Firma, ab.Abteilung, fu.Funktion From tblPerson p
inner join tblArbeitsort ar on ar.ArbeitsortID = p.Arbeitsort_fk
inner join tblFirmaHatAbteilungUndPersonHatFunktion zt on zt.Person_fk = p.PersonID
inner join tblFirma fi on fi.FirmaID = zt.Firma_fk
inner join tblAbteilung ab on ab.AbteilungID = zt.Abteilung_fk
inner join tblFunktion fu on fu.FunktionID = zt.Funktion_fk
WHERE 1 = 1'
IF (@Vorname IS NOT NULL) @SQL = @SQL + ' AND p.Vorname = @Vorname'
IF (@Nachname IS NOT NULL) @SQL = @SQL + ' AND p.Nachname = @Nachname'
-- other if conditions come here
EXEC sp_executesql @SQL, N'@Vorname VARCHAR(50), @Nachname VARCHAR(50)',
@Vorname = @Vorname, @Nachname = @Nachname
虽然dynamic SQL
没有从某些性能改进中受益,但事实上你的WHERE要简单得多(多个OR对性能不友好)可能会带来更好的结果。
答案 3 :(得分:0)
你不能轻易有效地做到这一点,这是一个很好的例子,为什么运行SP查询是一个死胡同。
你能做的最好的事情是:
WHERE ([x] LIKE @x AND @x IS NOT NULL)
与语句上的OPTION RECOMPILE
结合使用,以避免参数嗅探以确定可能错误的查询计划。