我想基于一个编码在CTE中执行select语句。类似下面的内容
;with CTE_AorB
(
if(condition)
select * from table_A
else
select * from table_B
),
CTE_C as
(
select * from CTE_AorB // processing is removed
)
但是我得到了错误。如果在CTE中有其他可能吗?如果没有,那就是一种解决方法或更好的方法。
感谢。
答案 0 :(得分:22)
尝试:
;with CTE_AorB
(
select * from table_A WHERE (condition true)
union all
select * from table_B WHERE NOT (condition true)
),
CTE_C as
(
select * from CTE_AorB // processing is removed
)
具有动态搜索条件的键是确保使用索引,这是一篇关于如何处理此主题的非常全面的文章:
Dynamic Search Conditions in T-SQL by Erland Sommarskog
它涵盖了尝试使用多个可选搜索条件编写查询的所有问题和方法。您需要关注的主要问题不是代码的重复,而是索引的使用。如果您的查询无法使用索引,那么它将执行不良。有几种技术可以使用,可能允许也可能不允许使用索引。
这是目录:
Introduction The Case Study: Searching Orders The Northgale Database Dynamic SQL Introduction Using sp_executesql Using the CLR Using EXEC() When Caching Is Not Really What You Want Static SQL Introduction x = @x OR @x IS NULL Using IF statements Umachandar's Bag of Tricks Using Temp Tables x = @x AND @x IS NOT NULL Handling Complex Conditions Hybrid Solutions – Using both Static and Dynamic SQL Using Views Using Inline Table Functions Conclusion Feedback and Acknowledgements Revision History
如果您使用的是适当版本的SQL Server 2008,则可以使用其他技术,请参阅:Dynamic Search Conditions in T-SQL Version for SQL 2008 (SP1 CU5 and later)
如果您使用的是SQL Server 2008的正确版本,则只需将OPTION (RECOMPILE)
添加到查询中,并在运行时将局部变量的值用于优化。
考虑到这一点,OPTION (RECOMPILE)
将采用此代码(其中没有索引可用于此OR
的混乱):
WHERE
(@search1 IS NULL or Column1=@Search1)
AND (@search2 IS NULL or Column2=@Search2)
AND (@search3 IS NULL or Column3=@Search3)
并在运行时优化它(假设只有@ Search2传入了一个值):
WHERE
Column2=@Search2
并且可以使用索引(如果在Column2上定义了一个索引)
答案 1 :(得分:3)
永远不要尝试在单个查询语句中放置IF等条件。即使你设法将它拉下来,这也是一种可靠的杀死性能的方法。请记住,单个语句意味着单个计划,并且必须以满足两个情况的方式生成计划,条件为true且条件为false时,立即。这通常会导致更糟糕的计划,因为'条件'通常会为计划创建互斥的访问路径,并且两者的结合始终是端到端的表扫描。
出于这个以及许多其他原因,你最好的方法是将IF放在声明之外:
if(condition true)
select * from table_A
else
select * from table_B
答案 2 :(得分:1)
我认为如果你的分支条件翻转,IF ELSE的东西可能会有很差的缓存。也许更有知识的人可以评论。
另一种方法是UNION ALL使用其他人建议的WHERE子句。 UNION ALL将取代IF ELSE
答案 3 :(得分:0)
如果您使用的是参数,那么您只需要一个语句。
@ID (Some parameter)
;with CTE
(
select * from table_A WHERE id = @ID
union all
select * from table_B WHERE (id = @ID and condition)
)