T-SQL 条件 WHERE 子句
在这里发现了几个类似的问题,但无法弄清楚如何应用于我的场景。
我的函数有一个名为 @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
如果@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.
如果@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)
显然这是不正确的。
正确的语法是什么?
Found a couple of similar questions here on this, but couldn't figure out how to apply to my scenario.
My function has a parameter called @IncludeBelow. Values are 0 or 1 (BIT).
I have this query:
SELECT p.*
FROM Locations l
INNER JOIN Posts p
on l.LocationId = p.LocationId
WHERE l.Condition1 = @Value1
AND l.SomeOtherCondition = @SomeOtherValue
If @IncludeBelow is 0, i need the query to be this:
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.
If @IncludeBelow is 1, that last line needs to be excluded. (i.e don't apply filter).
I'm guessing it needs to be a CASE
statement, but can't figure out the syntax.
Here's what i've tried:
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)
Obviously that's not correct.
What's the correct syntax?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我将查询更改为使用 EXISTS,因为如果有多个位置与 POST 关联,则会出现重复的 POST 记录,需要使用 DISTINCT 或 GROUP BY 子句来删除...
不可控制的
这将执行最糟糕的可能解决方案:
可控制的非动态版本 不
言自明...
可控制的动态版本 (SQL Server 2005+):
喜欢或讨厌它,动态 SQL 让您编写一次查询。请注意,sp_executesql 会缓存查询计划,这与 SQL Server 中的 EXEC 不同。在考虑 SQL Server 上的动态 SQL 之前,强烈建议阅读动态 SQL 的诅咒与祝福...
I changed the query to use EXISTS because if there's more than one location associated with a POST, there'd be duplicate POST records that'd require a DISTINCT or GROUP BY clause to get rid of...
The non-sargable
This will perform the worst of the possible solutions:
The sargable, non-dynamic version
Self explanitory....
The sargable, dynamic version (SQL Server 2005+):
Love or hate it, dynamic SQL lets you write the query once. Just be aware that sp_executesql caches the query plan, unlike EXEC in SQL Server. Highly recommend reading The Curse and Blessings of Dynamic SQL before considering dynamic SQL on SQL Server...
您可以将其编写为
您经常看到的模式,例如可选搜索参数。但是 IIRC 可能会扰乱查询执行计划,因此可能有更好的方法来做到这一点。
因为它只是一个位,所以几乎可能值得在带或不带检查的两个 SQL 块之间做出决定,例如,根据位在存储过程中使用 IF 或在调用代码中使用不同的命令字符串?
You can write it as
which is a pattern you see a lot e.g. for optional search parameters. But IIRC that can mess up the query execution plans so there may be a better way to do this.
Since it's only a bit, it almost might be worth deciding between two blocks of SQL with or without the check, e.g. using an IF in a stored procedure or with different command strings in calling code, based on the bit?
您可以将您的
CASE
语句更改为此。查询规划器对此有不同的看法,但它可能并不比使用 OR 更有效:You can change your
CASE
statement to this. The query planner sees this differently, but it may be no more efficient than using OR:按如下方式编辑 sql 语句:
不需要 @IncludeBelow 变量
包含所有位置类型 设置 @LocationType = '%'
限制查询返回的位置类型
Set @LocationType = '[A Specific Location Type]'
上述 Set 语句假定 @LocationType 变量是字符数据类型
Edit the sql statement as follows:
The @IncludeBelow variable is not needed
To include all location types Set @LocationType = '%'
To limit the location types returned by the query
Set @LocationType = '[A Specific Location Type]'
The above Set statements assume the @LocationType variable is character datatype