我的SSRS报告包含一个名为Brand的多值变量。
用户可以选择一个或多个不同的品牌。
这将传递给Microsoft SQL查询,基于此查询应该执行各种步骤。
示例:
如果BrandB在@Brand THEN中选择*来自数据库A中的东西;
如果BrandB在@Brand THEN中选择*来自数据库B中的东西;
如果BrandB在@Brand THEN中选择*来自数据库C中的东西;
这个的正确语法是什么?
另外,如何在放入我的报告之前在SQL中测试它?因为我认为你不能轻易地在SQL中创建多个值变量。 (或者我错了?)
或者,我可以让用户在选择中输入BrandA,BrandB,BrandC,然后说:
如果@Brand喜欢'%BrandA%'那么......
显然,第一种选择是更清洁,如果它真的有效。请帮忙。
答案 0 :(得分:3)
您可以使用:
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足够聪明,可以先计算常量表达式,没有必要时,不要费心阅读桌子。想象一下3个表(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中多值参数的性质: / p>
SELECT Brand = 2, ID, Filler
FROM T2
WHERE 2 IN (1, 3);
根本没有读物。
<强> EDIT2 强>
这仍然适用于OPENQUERY,以证明我已经删除了UNION(因为实际的IO读取被OPENQUERY略微屏蔽),但是使用了与上面相同的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行(s)受影响)
表'#3A17D891'。扫描计数1,逻辑读取2615,物理读取0,预读读取0,lob逻辑读取0,lob物理读取0,lob预读读取0。
(0行(s)受影响)
表'#3A17D891'。扫描计数1,逻辑读取1,物理读取0,预读取读取0,lob逻辑读取0,lob物理读取0,lob预读读取0。
(2615行(s)受影响)
表'#3A17D891'。扫描计数1,逻辑读取2615,物理读取0,预读读取0,lob逻辑读取0,lob物理读取0,lob预读读取0。
Agin显示T2
没有读取,因为外部where条件评估为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将您的三个结果合并为一个结果集。 e.g。
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子句中使用常量表达式执行查询,所以除了创建和插入临时表的开销之外,你实际上并没有从中做任何事情。
答案 1 :(得分:1)
你可以尝试这样的事情。
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