【问题标题】:Case in where Clause to find String in Parameter在 where 子句中在参数中查找字符串的情况
【发布时间】:2018-10-31 10:02:45
【问题描述】:

我的数据库 tblCustomer 中有一个表,它有 8 个布尔字段(MS01、MS02...MS08) 使用 SSRS 报告,我有一个多值参数下拉列表,允许选择 10 个值中的每一个 因此,如果我从列表中选择 MS01 和 MS05,参数 @idSite 将等于 'MS01','MS05'

'-1' = 真

我想从 tblCustomer 中选择所选参数值为 true 的所有记录

select idCustomer, MS01, MS02,MS03, MS04,MS05,MS06,MS07,MS08 from tblCustomer

WHERE     (tblCustomer.CustomerYN = '-1')
AND
CASE 
WHEN  @idSite like '%MS01%' THEN  tblCustomer.MS01=-1 
WHEN  @idSite like '%MS02%' THEN  tblCustomer.MS02=-1
WHEN  @idSite like '%MS03%' THEN  tblCustomer.MS03=-1
END as MailShot

当字符串在参数中时,我也尝试过使用

select idCustomer, MS01, MS02,MS03, MS04,MS05,MS06,MS07,MS08 from 
tblCustomer

WHERE     (tblCustomer.CustomerYN = '-1')
AND
CASE 
WHEN  'MS01' in @idSite THEN  tblCustomer.MS01=-1 
WHEN  'MS02' in @idSite THEN  tblCustomer.MS02=-1

END as MailShot

我以为我很接近上面的内容,但没有快乐。谁能指出我正确的方向?

编辑

@idSite 是 SSRS 多值参数下拉列表。 它根据下拉列表中的部分从下表中获取值 idMailshot

idMailShot  Location
MS01    Location1   
MS02    Location2     
MS03    Location3 
MS04    Location4  
MS05    Location5  
MS06    Location6     
MS07    Location7   
MS08    Location8   
MS09    Location9

所以如果我从下拉列表中选择位置 1 和位置 2,“MS01,MS02”应该作为@idSite 传递 我想要

select idCustomer from tblCustomer where
tblCustomer.MS01 =-1 AND tblCustomer.MS02=-1

【问题讨论】:

  • 您能提供一些示例数据和建议的输出吗?还。声明@idSite ='MS01','MS02','MS03';无效 - 输入是否为逗号分隔列表?
  • 为什么不使用bit 来保存您的标志/值1 为真,0 为假?为什么要传入一个字符串数组而不是为每个字段设置一个bit 参数?注意:您当前的代码将无法运行,因为 DECLARE @idSite ='MS01','MS02','MS03'; 无效/没有类型。
  • 应该是:declare @idSite table (MSFlag char(4)); insert @idSite (MSFlag) values ('MS01', 'MS02', 'MS03')
  • @idSite 是 SSRS 多值参数下拉列表。它根据下拉列表中的 idMailShot Location MS01 Location1 MS02 Location2 MS03 Location3 MS04 Location4 MS05 Location5 MS06 Location6 MS07 Location7 MS08 Location8 MS09 Location9 从下表中获取值 idMailshot

标签: sql-server string parameters case where-clause


【解决方案1】:

没有这样的方法可以在 Sql Server 变量中存储多个值,如下所示: DECLARE @idSite ='MS01','MS02','MS03';

但您可以通过以下方式在变量表中填充多个值:

declare @idSites table
(
  idSite varchar(100)
)
insert into @idSites (idSite) 
select COLUMN_NAME from Information_schema.Columns 
where TABLE_NAME = 'Table Name' and TABLE_CATALOG = 'Database Name'

如果你得到一个像这样的字符串"MS01,MS02,MS03" 那么你需要编写一个函数来生成一个基于comma分隔值的表,比如:

CREATE FUNCTION splitstring ( @stringToSplit VARCHAR(8000) )
    RETURNS
        @returnList TABLE ([Param] [nvarchar] (500))
AS
BEGIN

    DECLARE @name NVARCHAR(255)
    DECLARE @pos INT

    WHILE CHARINDEX(',', @stringToSplit) > 0
    BEGIN
        SELECT @pos  = CHARINDEX(',', @stringToSplit) 
        SELECT @name = SUBSTRING(@stringToSplit, 1, @pos-1)

        INSERT INTO @returnList
        SELECT @name

        SELECT @stringToSplit = SUBSTRING(@stringToSplit, @pos+1, LEN(@stringToSplit)-@pos)
    END
    INSERT INTO @returnList
    SELECT @stringToSplit
    RETURN
END

然后像这样使用它:

declare @StringVariable varchar(255) = "MS01,MS02,MS03";
Select [param] from splitstring(@StringVariable)

您的WHERE 子句也没有多大意义。我在下面写了一个测试环境,请看我是如何在那里维护WHERE子句的。

以下解决方案是假设数据,您可以将其复制粘贴到SQL Server 并执行。希望它能帮助您实现您想要的要求:)。

--Declaring table with multi values
declare @idSites table
(
    idSite varchar(100)
)
insert into @idSites values ('MS01')
insert into @idSites values ('MS02')
insert into @idSites values ('MS03')

--Assuming a table with columns and values added in below CTE
;with cte as (
select 
-1 as MS01
,2 as MS02
,-1 as MS03
,-1 as CustomerYN
union all
Select 
 2 as MS01
,-1 as MS02
,0 as MS03
,0 as CustomerYN
)
--Finally The query part to fetch the data as per understood from your question.
select 
*
from cte
where cte.CustomerYN = -1
   AND(
        (cte.MS01 =  -1 AND 'MS01' = (Select idSite from @idSites where idSite = 'MS01'))
        OR (cte.MS02 =  -1 AND 'MS02' = (Select idSite from @idSites where idSite = 'MS02'))
        OR (cte.MS03 =  -1 AND 'MS03' = (Select idSite from @idSites where idSite = 'MS03'))
      )

【讨论】:

    【解决方案2】:

    您的WHERE 毫无意义:

    WHERE     (tblCustomer.CustomerYN = '-1')
    AND
    CASE 
    WHEN  @idSite like '%MS01%' THEN  tblCustomer.MS01=-1 
    WHEN  @idSite like '%MS02%' THEN  tblCustomer.MS02=-1
    WHEN  @idSite like '%MS03%' THEN  tblCustomer.MS03=-1
    END as MailShot
    

    您的CASE 表达式作为一个整体不是布尔表达式,它在THEN 中有布尔表达式; CASE 返回一个标量值而不是布尔值。您还在您的WHERE 中为您的CASE 起别名。您不要在 WHERE 中为表达式添加别名。

    但是,与其使用 CASE 表达式(这会使您的查询不可搜索),不如使用布尔逻辑更好:

    WHERE tblCustomer.CustomerYN = -1 -- -1 is a int, pass it as one
      AND ((tblCustomer.MS01 = -1 AND @idSite like '%MS01%')
       OR  (tblCustomer.MS02 = -1 AND @idSite like '%MS02%')
       OR  (tblCustomer.MS03 = -1 AND @idSite like '%MS03%'))
    

    注意,如果您在 WHERE 中使用 CASE 表达式(尽管如我上面所说,这会导致它不可搜索),您需要返回一个标量值并创建一个布尔表达式。举个简单的例子:

    WHERE CASE @SomeID WHEN 1 THEN T.ColumnA
                       WHEN 2 THEN T.ColumnB
                       ELSE T.ColumnC
          END = 'Some Value'
    

    注意CASE 表达式返回一个标量值(ColumnAColumnBColumnC 的值),然后将该标量值与文字字符串'Some Value' 进行比较.你的布尔表达式不在THEN 中,它在CASE 表达式之外。

    【讨论】:

    • 这真的很接近。给我 MS01 MS02 的正确数字,但之后都是错误的。另外;如果我选择多个选项,@idSite 不会像我预期的那样处理为逗号分隔列表
    【解决方案3】:

    如果你想传递你正在做的值。您需要一个拆分功能。因为找不到您的价值组合。在这种情况下,您尝试将列标题值与存储在单元格中的值相比较。

    DECLARE @idSite ='MS01','MS02','MS03';
    

    您的替代方法是使用 CTE 动态构建查找表,然后在报告过程开始时将数据转储到临时表中。它将组合 10 个值并存储它们。然后你在你的过滤子句中动态地利用这个临时表。请记住“加入”条件(即,您将从主表加入到此临时表的列)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-01
      • 2015-03-07
      • 2013-10-17
      • 1970-01-01
      • 2013-08-24
      相关资源
      最近更新 更多