[英]SSRS: SQL 'IF' logic based on multiple value parameter
我的SSRS报告包含一个名为Brand的多值变量。
用户可以选择一个或多个不同的品牌。
这将传递给Microsoft SQL查询,并基于此查询应执行各种步骤。
例:
如果@Brand中的BrandA然后从数据库A中的内容中选择*;
如果@Brand中的BrandB然后从数据库B中的内容中选择*;
如果@Brand中的BrandB然后从数据库C中的内容中选择*;
正确的语法是什么?
另外,在放入报表之前如何在SQL中对其进行测试? 因为我不认为您可以在SQL中轻松创建多个值变量。 (或者我错了吗?)
或者,我可以在选择中将用户类型设置为BrandA,BrandB,BrandC,然后说:
如果@Brand喜欢'%BrandA%',则...
显然,第一种选择是更干净的,如果它确实可以工作的话。 请帮忙。
您可以使用:
SELECT Brand = 'BrandA', Column1, Column2, Column3
FROM Database1.dbo.Table
WHERE 'BrandA' IN (@Brand)
UNION ALL
SELECT Brand = 'BrandB', Column1, Column2, Column3
FROM Database2.dbo.Table
WHERE 'BrandB' IN (@Brand)
UNION ALL
SELECT Brand = 'BrandC', Column1, Column2, Column3
FROM Database3.dbo.Table
WHERE 'BrandC' IN (@Brand);
附录
关于注释,将@Brand
放在括号中的原因是因为这是如何在IN
语法中使用多值参数。
关于当您知道不需要结果时查询数据库效率低下,实际上您不会查询不需要的表的原因,SQL Server足够聪明,可以首先计算出常量表达式,而不必费心阅读不必要的桌子。 想象一下三个表(T1,T2,T3)完全相同,如下所示:
CREATE TABLE T1 (ID INT IDENTITY, Filler CHAR(1000));
INSERT T1 (Filler)
SELECT NULL FROM sys.all_objects;
现在,我们有3个相同的表,其中都填充了示例数据,然后运行此查询:
DECLARE @Brand TABLE (Brand INT);
INSERT @Brand (Brand) VALUES (1), (3);
SELECT Brand = 1, ID, Filler
FROM T1
WHERE 1 IN (SELECT Brand FROM @Brand)
UNION ALL
SELECT Brand = 2, ID, Filler
FROM T2
WHERE 2 IN (SELECT Brand FROM @Brand)
UNION ALL
SELECT Brand = 3, ID, Filler
FROM T3
WHERE 3 IN (SELECT Brand FROM @Brand);
SELECT *
FROM T1
WHERE 1 = 0
IO统计数据显示:
(受影响的5230行)
表'#1C299A82'。 扫描计数3,逻辑读5231,物理读0,预读0,lob逻辑读0,lob物理读0,lob预读0。
表“ T3”。 扫描计数1,逻辑读374,物理读0,预读0,lob逻辑读0,lob物理读0,lob预读0。
表“ T2”。 扫描计数1,逻辑读为1,物理读为0,预读为0,lob逻辑读为0,lob物理读为0,lob预读为0。
表“ T1”。 扫描计数1,逻辑读374,物理读0,预读0,lob逻辑读0,lob物理读0,lob预读0。
T2
的键实际上并未读取,显示为逻辑的读取是从@brand
读取,因为如果我要实际运行,则无法复制SSMS中多值参数的性质:
SELECT Brand = 2, ID, Filler
FROM T2
WHERE 2 IN (1, 3);
根本没有任何读物。
编辑2
这仍然可以与OPENQUERY一起使用,以演示我已经删除了UNION(因为OPENQUERY稍微掩盖了实际的IO读取),但是使用了与上述相同的3个测试表:
SET STATISTICS IO ON;
DECLARE @Brand TABLE (Brand INT);
INSERT @Brand (Brand) VALUES (1), (3);
SELECT Brand = 1, ID, Filler
FROM OPENQUERY([ServerName], 'SELECT ID, Filler FROM TestDB.dbo.T1')
WHERE 1 IN (SELECT Brand FROM @Brand)
SELECT Brand = 2, ID, Filler
FROM OPENQUERY([ServerName], 'SELECT ID, Filler FROM TestDB.dbo.T2')
WHERE 2 IN (SELECT Brand FROM @Brand)
SELECT Brand = 3, ID, Filler
FROM OPENQUERY([ServerName], 'SELECT ID, Filler FROM TestDB.dbo.T3')
WHERE 3 IN (SELECT Brand FROM @Brand);
(受影响的2615行)
表'#3A17D891'。 扫描计数1,逻辑读2615,物理读0,预读0,lob逻辑读0,lob物理读0,lob预读0。
(0行受影响)
表'#3A17D891'。 扫描计数1,逻辑读为1,物理读为0,预读为0,lob逻辑读为0,lob物理读为0,lob预读为0。
(受影响的2615行)
表'#3A17D891'。 扫描计数1,逻辑读2615,物理读0,预读0,lob逻辑读0,lob物理读0,lob预读0。
再次,这表明在T2
上没有读取,因为外部条件条件评估为false,再次在品牌表上进行了一次读取,使用常量运行以下命令不会产生读取:
SELECT Brand = 2, ID, Filler
FROM OPENQUERY([ServerName], 'SELECT ID, Filler FROM TestDB.dbo.T2')
WHERE 2 IN (1, 3);
我建议UNION ALL
组合所有查询而不是使用IF
是,您需要为所有可能的品牌组合创建条件,使用临时表,或者使用动态SQL将三个结果组合为一个结果集。 例如
IF 'BrandA' IN (@Brand)
BEGIN
SELECT <Columns>
FROM Database1.dbo.Table
END
IF 'BrandB' IN (@Brand)
BEGIN
SELECT <Columns>
FROM Database1.dbo.Table
END
IF 'BrandC' IN (@Brand)
BEGIN
SELECT <Columns>
FROM Database2.dbo.Table
END
每个品牌将产生一组结果,您的SSRS数据集将仅使用其中之一,为避免使用动态SQL或临时表,您将需要以下内容:
IF 'BrandA' IN (@Brand) AND 'BrandB' IN (@Brand) AND 'BrandC' IN (@Brand)
BEGIN
--UNION ALL THREE TOGETHER
END
ELSE IF 'BrandA' IN (@Brand) AND 'BrandB' IN (@Brand)
BEGIN
--UNION ALL BRANDA AND BRANDB TOGETHER
END
ELSE IF 'BrandA' IN (@Brand) AND 'BrandC' IN (@Brand)
BEGIN
--UNION ALL BRANDA AND BRANDC TOGETHER
END
ELSE IF 'BrandA' IN (@Brand)
BEGIN
--JUST BRANDA
END
ELSE IF 'BrandB' IN (@Brand) AND 'BrandC' IN (@Brand)
BEGIN
--UNION ALL BRANDB AND BRANDC TOGETHER
END
ELSE IF 'BrandB' IN (@Brand)
BEGIN
--JUST BRANDB
END
ELSE IF 'BrandC' IN (@Brand)
BEGIN
--JUST BRANDC
END
我认为您会同意,只有3个可能的值已经够糟糕的了,如果您拥有更多的值,它将变得很可笑。 临时表可能是一种可行的方法:
SET NOCOUNT ON;
CREATE TABLE #T (<columns>);
IF 'BrandA' IN (@Brand)
BEGIN
INSERT #T (<columns>)
SELECT <Columns>
FROM Database1.dbo.Table
END
IF 'BrandB' IN (@Brand)
BEGIN
INSERT #T (<columns>)
SELECT <Columns>
FROM Database1.dbo.Table
END
IF 'BrandC' IN (@Brand)
BEGIN
INSERT #T (<columns>)
SELECT <Columns>
FROM Database2.dbo.Table
END
SELECT *
FROM #T;
但是如所示,您实际上并未在where子句中使用常量表达式执行查询,因此,除了创建和插入临时表的开销之外,您实际上没有从中获得任何好处。
您可以尝试这样。
DECLARE @Brand
IF BrandA IN (@Brand)
BEGIN
USE DATABASE_A
SELECT * FROM TABLE
END
ELSE IF BrandB IN (@Brand)
BEGIN
USE DATABASE_B
SELECT * FROM TABLE
END
ELSE
BEGIN
USE DEFAUL_DATABASE
SELECT * FROM Table
END
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.