简体   繁体   English

WHERE子句中的CASE语句(SQL Server)

[英]CASE Statement in WHERE Clause (SQL Server)

I am using Case statement in WHERE clause for SQL Server. 我在SQL Server的WHERE子句中使用Case语句。 However, the values I have in THEN clause is a list of integer. 但是,我在THEN子句中的值是一个整数列表。 Is there any other way of doing this in a WHERE clause? WHERE子句中还有其他方法可以这样做吗? OrderIds are in drop-down list, so either 30, 40 or 50 is selected of it none is selected, then orderID IN (30, 40, 50). OrderIds在下拉列表中,因此选择了30、40或50,但未选择任何一个,然后选择了orderID IN(30、40、50)。 PS I can't do @OrderID IS NULL otherwise it will search for every orderid in the database. PS我不能做@OrderID IS NULL,否则它将搜索数据库中的每个orderid。 So either one value or default (30,40,50) 因此,一个值或默认值(30,40,50)

WHERE 
    1 = 1
    AND [Order].[ORDERID] IN 
        (CASE WHEN @ORDERID IS NOT NULL
            THEN @ORDERID 
        ELSE
            THEN ('30,40,50')
        END)

I keep getting an error 我不断收到错误消息

Conversion failed when converting the varchar value '30,40,50' to data type int 将varchar值'30,40,50'转换为数据类型int时转换失败

Do not use a case expression . 不要使用case 表达式 Just use basic logic: 只需使用基本逻辑:

WHERE 1 = 1 AND
      (@OrderId IS NULL OR [Order].OrderId in (30, 40, 50))

I would also advise you to name your tables so they do not conflict with SQL keywords. 我还建议您为表命名,以免它们与SQL关键字冲突。 Your table could be named Orders for instance. 例如,您的表可以命名为Orders

Also, I assume the string representation for the list is unnecessary. 另外,我认为列表的字符串表示形式是不必要的。 Otherwise, that introduces other issues (if you are representing a list as a string). 否则,这会带来其他问题(如果您将列表表示为字符串)。

EDIT: 编辑:

I'm worried that the actual logic you want is: 我担心您想要的实际逻辑是:

WHERE 1 = 1 AND
      ((@OrderId IS NULL AND [Order].OrderId in (30, 40, 50)) OR
       ([Order].OrderId = @OrderId)
      )

This works, as long as you have a single value in @OrderId . 只要您在@OrderId具有单个值,此方法就@OrderId

CASE expressions result in values . CASE表达式产生 You can't use them to produce expressions , such as the value list expression you're trying to use. 您不能使用它们来生成表达式 ,例如您要使用的值列表表达式。 You need to re-think how you structure this so you can just use a value. 您需要重新考虑如何构造它,以便只使用一个值。

One way to do this is to split the case expression so each possible WHEN result is it's own condition, and the alternative result from each condition will produce true : 一种方法是拆分case表达式,以便每个可能的WHEN结果都是它自己的条件,并且每个条件的替代结果将产生true

WHERE 
    1 = 1
    AND [Order].[ORDERID] = coalesce(@ORDERID, [Order].[ORDERID])
    AND case when @orderid is null then [Order].[ORDERID] ELSE 30 end IN (30, 40, 50)

There's usually a simpler way to write the expression, but this illustrates a reliable way to make the conversion from incorrect CASE to correct WHERE. 通常有一种写表达式的简单方法,但这说明了一种可靠的方法,可以将错误的CASE转换为正确的WHERE。

If your numbers are a comma separated string of numbers , you can use this code: 如果您的数字是逗号分隔的数字字符串 ,则可以使用以下代码:

DECLARE @LIST VARCHAR(200)
SET @LIST = '30, 40, 50'

---------------------------
WHERE 1 = 1 AND
     (
      @OrderId IS NULL
      OR
      [Order].OrderId in (SELECT * FROM dbo.SplitStrings_Moden(@LIST,N','))
     )

To use the above code you need to define the following function in your DB to get a Table from comma separated string of numbers: 要使用上面的代码,您需要在数据库中定义以下函数,以逗号分隔的数字字符串获取表格:

CREATE FUNCTION dbo.SplitStrings_Moden
(
   @List NVARCHAR(MAX),
   @Delimiter NVARCHAR(255)
)
RETURNS TABLE
WITH SCHEMABINDING AS
RETURN
  WITH E1(N)        AS ( SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 
                         UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 
                         UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1),
       E2(N)        AS (SELECT 1 FROM E1 a, E1 b),
       E4(N)        AS (SELECT 1 FROM E2 a, E2 b),
       E42(N)       AS (SELECT 1 FROM E4 a, E2 b),
       cteTally(N)  AS (SELECT 0 UNION ALL SELECT TOP (DATALENGTH(ISNULL(@List,1))) 
                         ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E42),
       cteStart(N1) AS (SELECT t.N+1 FROM cteTally t
                         WHERE (SUBSTRING(@List,t.N,1) = @Delimiter OR t.N = 0))
  SELECT Item = SUBSTRING(@List, s.N1, ISNULL(NULLIF(CHARINDEX(@Delimiter,@List,s.N1),0)-s.N1,8000))
    FROM cteStart s;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM