SSRS:SQL' IF'基于多值参数的逻辑

时间:2014-05-21 08:13:49

标签: sql variables reporting-services

我的SSRS报告包含一个名为Brand的多值变量。

用户可以选择一个或多个不同的品牌。

这将传递给Microsoft SQL查询,基于此查询应该执行各种步骤。

示例:

如果BrandB在@Brand THEN中选择*来自数据库A中的东西;

如果BrandB在@Brand THEN中选择*来自数据库B中的东西;

如果BrandB在@Brand THEN中选择*来自数据库C中的东西;

这个的正确语法是什么?

另外,如何在放入我的报告之前在SQL中测试它?因为我认为你不能轻易地在SQL中创建多个值变量。 (或者我错了?)

或者,我可以让用户在选择中输入BrandA,BrandB,BrandC,然后说:

如果@Brand喜欢'%BrandA%'那么......

显然,第一种选择是更清洁,如果它真的有效。请帮忙。

2 个答案:

答案 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