RPM*_*984 28 sql t-sql sql-server case-statement where-clause
在这里找到了几个类似的问题,但无法弄清楚如何应用于我的场景.
我的函数有一个名为@IncludeBelow的参数.值为0或1(BIT).
我有这个问题:
SELECT p.*
FROM Locations l
INNER JOIN Posts p
on l.LocationId = p.LocationId
WHERE l.Condition1 = @Value1
AND l.SomeOtherCondition = @SomeOtherValue
Run Code Online (Sandbox Code Playgroud)
如果@IncludeBelow为0,我需要查询为:
SELECT p.*
FROM Locations l
INNER JOIN Posts p
on l.LocationId = p.LocationId
WHERE l.Condition1 = @Value1
AND l.SomeOtherCondition = @SomeOtherValue
AND p.LocationType = @LocationType -- additional filter to only include level.
Run Code Online (Sandbox Code Playgroud)
如果@IncludeBelow为1,则需要排除最后一行.(即不要应用过滤器).
我猜它需要是一个CASE
声明,但无法弄清楚语法.
这是我尝试过的:
SELECT p.*
FROM Locations l
INNER JOIN Posts p
on l.LocationId = p.LocationId
WHERE l.Condition1 = @Value1
AND l.SomeOtherCondition = @SomeOtherValue
AND (CASE @IncludeBelow WHEN 0 THEN p.LocationTypeId = @LocationType ELSE 1 = 1)
Run Code Online (Sandbox Code Playgroud)
显然这不正确.
什么是正确的语法?
OMG*_*ies 39
我将查询更改为使用EXISTS,因为如果有多个POST关联的位置,则会有重复的POST记录需要DISTINCT或GROUP BY子句来摆脱...
这将执行最糟糕的解决方案:
SELECT p.*
FROM POSTS p
WHERE EXISTS(SELECT NULL
FROM LOCATIONS l
WHERE l.LocationId = p.LocationId
AND l.Condition1 = @Value1
AND l.SomeOtherCondition = @SomeOtherValue)
AND (@IncludeBelow = 1 OR p.LocationTypeId = @LocationType)
Run Code Online (Sandbox Code Playgroud)
自我解释....
BEGIN
IF @IncludeBelow = 0 THEN
SELECT p.*
FROM POSTS p
WHERE EXISTS(SELECT NULL
FROM LOCATIONS l
WHERE l.LocationId = p.LocationId
AND l.Condition1 = @Value1
AND l.SomeOtherCondition = @SomeOtherValue)
AND p.LocationTypeId = @LocationType
ELSE
SELECT p.*
FROM POSTS p
WHERE EXISTS(SELECT NULL
FROM LOCATIONS l
WHERE l.LocationId = p.LocationId
AND l.Condition1 = @Value1
AND l.SomeOtherCondition = @SomeOtherValue)
END
Run Code Online (Sandbox Code Playgroud)
喜欢或讨厌它,动态SQL允许您编写一次查询.请注意,与SQL Server中的EXEC不同,sp_executesql会缓存查询计划.强烈建议在考虑SQL Server上的动态SQL之前阅读动态SQL的诅咒和祝福 ......
DECLARE @SQL VARCHAR(MAX)
SET @SQL = 'SELECT p.*
FROM POSTS p
WHERE EXISTS(SELECT NULL
FROM LOCATIONS l
WHERE l.LocationId = p.LocationId
AND l.Condition1 = @Value1
AND l.SomeOtherCondition = @SomeOtherValue)'
SET @SQL = @SQL + CASE
WHEN @IncludeBelow = 0 THEN
' AND p.LocationTypeId = @LocationType '
ELSE ''
END
BEGIN
EXEC sp_executesql @SQL,
N'@Value1 INT, @SomeOtherValue VARCHAR(40), @LocationType INT',
@Value1, @SomeOtherValue, @LocationType
END
Run Code Online (Sandbox Code Playgroud)
Rup*_*Rup 11
你可以把它写成
SELECT p.*
FROM Locations l
INNER JOIN Posts p
ON l.LocationId = p.LocationId
WHERE l.Condition1 = @Value1
AND l.SomeOtherCondition = @SomeOtherValue
AND ((@IncludeBelow = 1) OR (p.LocationTypeId = @LocationType))
Run Code Online (Sandbox Code Playgroud)
这是您看到很多例如可选搜索参数的模式.但IIRC可能会破坏查询执行计划,因此可能有更好的方法来执行此操作.
由于它只是一点点,几乎可能值得在两个SQL块之间进行有或没有检查,例如在存储过程中使用IF或在调用代码中使用不同的命令字符串,基于位?