Dynamic SQL: 用于 SSRS 数据集查询的 HAVING 子句中的 CASE 表达式

Dynamic SQL: CASE expression in HAVING clause for SSRS dataset query

我的一个表包含 6 位标志:

tblDocumentFact.useCase1
tblDocumentFact.useCase2
tblDocumentFact.useCase3
tblDocumentFact.useCase4
tblDocumentFact.useCase5
tblDocumentFact.useCase6 

位标志用于通过HAVING子句限制返回的数据,例如:

HAVING tblDocumentFact.useCase4 = 1     /* '1' means 'True' */

这适用于静态查询。查询是针对 SQL Server Reporting Services 报告的数据集。我不想有 6 个报告,每个位标志一个,而是有 1 个带有 @UserChoice 输入参数的报告。我正在尝试编写一个动态查询来根据 @UserChoice 参数构建 HAVING 子句。我认为当用户单击 1-of-6 选项按钮时,@UserChoice 可以设置为整数值(1、2、3、4、5 或 6)。我已尝试通过 CASE 表达式执行此操作,如下所示,但它不起作用——查询 returns 没有行。这里的正确方法是什么?

HAVING  (
        (CASE WHEN @UserChoice =1 THEN 'dbo.tblDocumentFact.useCase1' END) = '1'
  OR    (CASE WHEN @UserChoice =2 THEN 'dbo.tblDocumentFact.useCase2' END) = '1' 
  OR    (CASE WHEN @UserChoice =3 THEN 'dbo.tblDocumentFact.useCase3' END) = '1' 
  OR    (CASE WHEN @UserChoice =4 THEN 'dbo.tblDocumentFact.useCase4' END) = '1' 
  OR    (CASE WHEN @UserChoice =5 THEN 'dbo.tblDocumentFact.useCase5' END) = '1' 
  OR    (CASE WHEN @UserChoice =6 THEN 'dbo.tblDocumentFact.useCase6' END) = '1' 
        )

您需要稍微改写一下您的逻辑:

HAVING
    (@UserChoice = 1 AND 'dbo.tblDocumentFact.useCase1' = '1') OR
    (@UserChoice = 2 AND 'dbo.tblDocumentFact.useCase2' = '2') OR
    (@UserChoice = 3 AND 'dbo.tblDocumentFact.useCase3' = '3') OR
    (@UserChoice = 4 AND 'dbo.tblDocumentFact.useCase4' = '4') OR
    (@UserChoice = 5 AND 'dbo.tblDocumentFact.useCase5' = '5') OR
    (@UserChoice = 6 AND 'dbo.tblDocumentFact.useCase6' = '6');

A​​ CASE 表达式不能按照您使用它的方式使用,因为 THENELSE 后面必须是文字值,而不是逻辑条件.

稍微扩展一下蒂姆 post 下的评论,我认为它不起作用的原因是因为您的案例发出的字符串包含列名而不是列

的值
HAVING
  CASE WHEN @UserChoice = 1 THEN dbo.tblDocumentFact.useCase1 END = 1
  OR CASE WHEN @UserChoice = 2 THEN dbo.tblDocumentFact.useCase2 END = 1
 ...

它甚至可能清理到这个:

拥有 案例@UserChoice 当 1 那么 dbo.tblDocumentFact.useCase1 当 2 那么 dbo.tblDocumentFact.useCase2 ... 结束 = 1

问题(我相信;至少在 sql 服务器中,不完全确定 SSRS)是当你说:

CASE WHEN @UserChoice = 1 THEN 'dbo.tblDocumentFact.useCase1' END = '1'

您的情况是发出文字字符串 dbo.tblDocumentFact.useCase1 而不是该行上该列的值。当然,这个文字字符串永远不会等于 1

的文字字符串

总的来说,我更喜欢蒂姆的解决方案;我认为查询优化器更有可能在这种形式的位列上使用索引,但要注意使用 OR 会导致 sql 服务器忽略索引;我老地方的 DBA 经常重写如下查询:

SELECT * FROM Person WHERE FirstName = 'john' OR LastName = 'Smith'

进入这个:

SELECT * FROM Person WHERE FirstName = 'john' 
UNION
SELECT * FROM Person WHERE LastName = 'Smith'

因为当我们使用 OR 时,服务器不会将 FirstName 上的索引和 LastName 上的另一个索引组合起来,但是它会以 UNION 形式使用两个索引并行执行

考虑作为替代方案,将这些位标志组合成一个整数,作为二进制 2 的补码(如果您希望能够通过搜索 3 或选择 2 来表示用户选择 1 和 2和 4 和 6 通过搜索 42 [2^(2 -1) + 2^(4-1) + 2^(6-1)]) 或者只是一个可以与@userChoice 比较的直接整数,并索引它