SSRS参数的SQL Server转义字符问题

时间:2017-08-28 17:34:22

标签: sql-server reporting-services escaping ssrs-2012

在SSRS中,我有一个办公室管理员名称参数,由存储过程填充:

   SELECT
            MANAGER.office_manager_name
        FROM  (SELECT
                     ISNULL(REPLACE(PRACT_LOC.officemanagername, ',', ''), '*N/A') AS office_manager_name
                     FROM  PRACTICELOCATIONS PRACT_LOC 
                     UNION
                     SELECT
                     '*N/A') MANAGER
        ORDER  BY
            MANAGER.office_manager_name

参数填充如下:

   *N/A, Smith John, Sharp Alex, O'Toole Tom

在SQL Server中,我有另一个SP,它使用函数分割器从表中连接office manager名称:

    CREATE PROCEDURE IP
    (@office_manager_name VARCHAR(4000))
    AS

    Select * from Table A
    where ISNULL(REPLACE(A.officemanagername, ',', ''), '*N/A') IN (SELECT item FROM   DBO.FNSPLIT(@officemanagername, ','))

功能拆分器代码如下所示:

    ALTER FUNCTION [dbo].[fnSplit]
    (
@sInputList VARCHAR(MAX), -- List of delimited items
@sDelimiter VARCHAR(MAX) = ',' -- delimiter that separates items
    ) 

    RETURNS @List TABLE (item VARCHAR(MAX))

   BEGIN

   DECLARE @sItem VARCHAR(MAX)

    WHILE CHARINDEX(@sDelimiter,@sInputList,0) <> 0
BEGIN
    SELECT
      @sItem=RTRIM(LTRIM(SUBSTRING(@sInputList,1,CHARINDEX      (@sDelimiter,@sInputList,0)-1))),
      @sInputList=RTRIM(LTRIM(SUBSTRING(@sInputList,CHARINDEX(@sDelimiter,@sInputList,0)+LEN(@sDelimiter),LEN(@sInputList))))

    IF LEN(@sItem) > 0
        INSERT INTO @List SELECT @sItem
END

IF LEN(@sInputList) > 0
    INSERT INTO @List SELECT @sInputList -- Put the last item in
    RETURN

     END         

我遇到的问题是,如果我从参数中选择所有经理,那么办公室经理Tom O'Toole的任何记录都不会显示在报告中。如果我只是从参数列表中选择O'Toole Tom,他确实会出现。我认为这与他的姓氏中的撇号有关,因为他是唯一有撇号的经理。如果是这种情况,是否有人知道如何在此代码中使用转义字符来让O'Toole填充?

3 个答案:

答案 0 :(得分:1)

我使用SQL Server Profiler发现了这个问题。 报告发送到服务器的是:

exec rsp_m_initialprocessxxxx @practice_manager=N'*N/A,O''''Toole Tom,Sharp Alex,Smith John'

正如你所看到的那样,而不是2个撇号,它正在发送4:O''''Toole Tom

使用DBO.FNSPLIT分割此sting时,您已O''Toole Tom而不是O'Toole Tom,而且您的表中找不到匹配项。

workaroud如下:在你的存储过程中用这样的2替换4个撇号,添加额外的变量@ practice_manager1:

declare @practice_manager1 varchar(4000) = (select replace(@practice_manager, replicate(char(39), 2), replicate(char(39), 1)));

Select * from dbo.A
where ISNULL(REPLACE(A.office_manager_name, ',', ''), '*N/A') IN (SELECT item FROM DBO.FNSPLIT(@practice_manager1, ','));

Char(39)是撇号,我使用它的代码代替符号而不会变得疯狂'''''

P.S。您使用的是SSRS 2016,而非2012年

<强> UPDATE1

  

我刚试过这个,但它仍然不起作用。如果我,它也行不通   只需选择Tom O'Toole而不是之前有效的All。

我已经为这两种情况再次测试了这段代码,这是我的代表:

declare @t table (test_num int, name varchar(4000)); 
insert into @t values (1, 'O''Toole Tom'),
(2, '*N/A,O''''Toole Tom,Sharp Alex,Smith John');

SELECT test_num, name, item 
FROM @t cross apply DBO.FNSPLIT(name, ',');

SELECT test_num, name, item 
FROM @t cross apply DBO.FNSPLIT(replace(name, replicate(char(39), 2), replicate(char(39), 1)), ',');

我为这两种情况插入了2个字符串并直接将DBO.FNSPLIT应用于这些字符串,并且在制作replace之后,第二种方式适用于这两种情况:

enter image description here

<强> UPDATE2

如何找到传递给存储过程的第一个参数。

首先改变您的程序,这将使旧计划无效。 然后使用有问题的参数从SSRS运行它。这个参数将被嗅探,因为它是第一次执行。然后,您可以以图形方式或在程序计划的xml中将其视为ParameterCompiledValue

以下是从缓存中获取proc计划的代码:

select qp.query_plan
from sys.dm_exec_procedure_stats ps
     cross apply sys.dm_exec_query_plan(ps.plan_handle) qp
where object_id = object_id('dbo.sp_test'); -- put here your sp name

enter image description here

答案 1 :(得分:0)

问题是&#34;&#39;&#34;在Ton的名称中的符号,尝试添加替换波纹的代码

  REPLACE(@officemanagername,'''','''''')

----
CREATE PROCEDURE ##IP
    (@office_manager_name VARCHAR(4000))
    AS

    Select * from Table A
    where ISNULL(REPLACE(A.officemanagername, ',', ''), '*N/A') IN (SELECT item FROM   DBO.FNSPLIT(REPLACE(@officemanagername,'''',''''''), ','))

答案 2 :(得分:0)

我的存储过程遇到了同样的问题。

在我的过程REPLACE(@param,'''','''''')中减少引号是可行的。但是,在SSRS之外调用我的过程不适用于真正的2个单引号。

有一个更好的解决方案。您可以加入报告参数,然后再将其传递给过程

Join(Parameters!Value.Value, ",")