繁体   English   中英

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

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM