我想在select语句中使用“CASE WHEN ... THEN 1 ELSE 0 END”的句子。棘手的部分是我需要它来处理“值IN @List”。
如果我对列表进行硬编码,那么它的工作正常 - 而且效果很好:
SELECT
CASE WHEN t.column_a IN ( 'value a', 'value b' ) THEN 1 ELSE 0 END AS priority
, t.column_b
, t.column_c
FROM
table AS t
ORDER BY
priority DESC
我想做的是:
-- @AvailableValues would be a list (array) of strings.
DECLARE
@AvailableValues ???
SELECT
@AvailableValues = ???
FROM
lookup_table
SELECT
CASE WHEN t.column_a IN @AvailableValues THEN 1 ELSE 0 END AS priority
, t.column_b
, t.column_c
FROM
table AS t
ORDER BY
priority DESC
不幸的是,似乎SQL Server没有这样做 - 你不能使用带有IN子句的变量。所以这给我留下了一些其他的选择:
还有其他选择吗?性能非常对于查询非常重要 - 它必须非常快,因为它为网站提供实时搜索结果页面(即没有缓存)。
这里还有其他选择吗?有没有办法改善上述选项之一的性能以获得良好的性能?
提前感谢您提供任何帮助!
更新:我应该提到上例中的'lookup_table'已经是一个表变量。我还更新了示例查询,以更好地演示我如何使用该子句。
更新II:我发现IN子句在NVARCHAR / NCHAR字段下运行(由于历史表设计原因)。如果我要进行处理整数字段的更改(即通过PK / FK关系约束),这会对性能产生很大影响吗?
答案 0 :(得分:7)
您可以在IN
子句中使用变量,但不能按照您尝试的方式使用。例如,你可以这样做:
declare @i int
declare @j int
select @i = 10, @j = 20
select * from YourTable where SomeColumn IN (@i, @j)
关键是变量不能代表多个值。
要回答您的问题,请使用内联选择。只要您不在查询中引用外部值(可能会逐行更改结果),引擎就不会重复从表中选择相同的数据。
答案 1 :(得分:2)
根据您的更新并假设查找表很小,我建议您尝试以下内容:
DECLARE @MyLookup table
(SomeValue nvarchar(100) not null)
SELECT
case when ml.SomeValue is not null then 1 else 0 end AS Priority
,t.column_b
,t.column_c
from MyTable t
left outer join @MyLookup ml
on ml.SomeValue = t.column_a
order by case when ml.SomeValue is not null then 1 else 0 end desc
(您不能在ORDER BY子句中引用列别名“Priority”。或者,您可以使用序号位置,如下所示:
order by 1 desc
但通常不建议这样做。)
只要查找表很小,这确实应该很快运行 - 但是你的评论意味着它是一个非常大的表,这可能会降低性能。
至于n [Var] char与int,是的,整数会更快,如果只是因为CPU有更少的字节来处理......这只是处理批次时的一个问题 of rows,所以值得尝试。
答案 2 :(得分:1)
这可能与您所需要的一致 请注意,这假定您具有权限并且已对输入数据进行了清理。
来自Running Dynamic Stored Procedures
CREATE PROCEDURE MyProc (@WHEREClause varchar(255))
AS
-- Create a variable @SQLStatement
DECLARE @SQLStatement varchar(255)
-- Enter the dynamic SQL statement into the
-- variable @SQLStatement
SELECT @SQLStatement = "SELECT * FROM TableName WHERE " + @WHEREClause
-- Execute the SQL statement
EXEC(@SQLStatement)
答案 3 :(得分:1)
我使用CHARINDEX函数解决了这个问题。我想将字符串作为单个参数传递。我创建了一个字符串,其中包含我想要测试的每个值的前导和尾随逗号。然后我将一个前导和尾随逗号连接到我想要查看的字符串是否在“参数”中。最后,我检查了CHARINDEX> 0
DECLARE @CTSPST_Profit_Centers VARCHAR (256)
SELECT @CTSPST_Profit_Centers = ',CS5000U37Y,CS5000U48B,CS5000V68A,CS5000V69A,CS500IV69A,CS5000V70S,CS5000V79B,CS500IV79B,'
SELECT
CASE
WHEN CHARINDEX(','+ISMAT.PROFIT_CENTER+',' ,@CTSPST_Profit_Centers) > 0 THEN 'CTSPST'
ELSE ISMAT.DESIGN_ID + ' 1 CPG'
END AS DESIGN_ID
您也可以在where子句
中执行此操作WHERE CHARINDEX(','+ISMAT.PROFIT_CENTER+',',@CTSPST_Profit_Centers) > 0
如果您尝试比较数字,则需要将数字转换为文本字符串,以使CHARINDEX函数正常工作。