Sqlserver 2014:无法在动态查询中使用表值函数

时间:2016-12-28 10:26:15

标签: sql sql-server dynamic-sql

我有这个表值函数,它通过在分隔符的基础上拆分字符串来创建表。

USE [sysmon]
GO
/****** Object:  UserDefinedFunction [dbo].[ParseString3]    Script Date: 12/28/2016 3:49:06 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER OFF
GO


ALTER FUNCTION [dbo].[ParseString3] (@String VARCHAR(MAX), @Delimiter VARCHAR(10))
RETURNS TABLE
AS

RETURN (
SELECT Ident, StringValue FROM 
    (
        SELECT Num as Ident,
            CASE 
                WHEN DATALENGTH(@delimiter) = 0 or @delimiter IS NULL
                    THEN SUBSTRING(@string, num, 1) 
            ELSE
                LTRIM(RTRIM(SUBSTRING(@String,
                    CASE 
                        WHEN (Num = 1 AND SUBSTRING(@String,num ,DATALENGTH(@delimiter)) <> @delimiter) THEN 1
                        ELSE Num + DATALENGTH(@delimiter)
                    END,
                    CASE CHARINDEX(@Delimiter, @String, Num + DATALENGTH(@delimiter))
                        WHEN 0 THEN LEN(@String) - Num + DATALENGTH(@delimiter)
                        ELSE CHARINDEX(@Delimiter, @String, Num + DATALENGTH(@delimiter)) - Num -
                            CASE 
                                WHEN Num > 1 OR (Num = 1 AND SUBSTRING(@String,num ,DATALENGTH(@delimiter)) = @delimiter) 
                                       THEN DATALENGTH(@delimiter)
                                ELSE 0
                            END
                       END
                    ))) 
              End  AS StringValue
        FROM sysmon.dbo.Numbers
        WHERE Num <= LEN(@String)
            AND (   
                    SUBSTRING(@String, Num, DATALENGTH(ISNULL(@delimiter,''))) = @Delimiter
                    OR Num = 1
                    OR DATALENGTH(ISNULL(@delimiter,'')) = 0 
                ) 
    ) R WHERE DATALENGTH(StringValue) <> 0
)

现在我正在创建动态查询

declare @abc nvarchar(500)

       set  @abc = 'select distinct stringvalue, ' + [sysmon].[dbo].[feedmapping]('sungard') +
            'from ' + [sysmon].[dbo].[parseString3]('599362,16570,568838',',') +
            ' inner join dbname.dbo.tablename  
            on stringvalue = tablecolumn'
exec sp_executesql @abc

其中feedmapping是另一个标量值函数

USE [sysmon]
GO
/****** Object:  UserDefinedFunction [dbo].[FeedMapping]    Script Date: 12/28/2016 4:07:59 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER FUNCTION [dbo].[FeedMapping](@feedName Varchar(20))
RETURNS VARCHAR(20)
AS
BEGIN
    DECLARE @ret VARCHAR(20)
    IF ( @feedname = 'SunGard')
        set @ret = 'SungardSymbol'
    ELSE IF ( @feedname = 'xxxx')
        set @ret = 'yyyyyyy'
    ELSE IF ( @feedname = 'aaaaa')
        set @ret = 'ccccccc'
    return @ret
END

在运行它时会给我以下错误

  

找不到任何一列&#34; sysmon&#34;或用户定义的函数或   aggregate&#34; sysmon.dbo.parseString3&#34;,或名称不明确。

请帮忙

2 个答案:

答案 0 :(得分:0)

动态SQL启动新会话(SID)。具有当前权限的会话在动态sql会话中不可用。您无权对象[sysmon]。

还有一件事。你可以很容易地分割字符串。尝试使用代码:

CREATE FUNCTION [dbo].[str__split](
     @str           NVARCHAR(MAX)
    ,@delimiter     NVARCHAR(MAX)
)
RETURNS @split TABLE(
     [str] NVARCHAR(MAX)
)
AS
BEGIN

    INSERT INTO @split(
         [str]
    )
    SELECT 
        [X].[C].[value]('(./text())[1]', 'nvarchar(4000)')
    FROM 
        ( 
            SELECT 
                [X] = CONVERT(XML, '<i>' + REPLACE(@str, @delimiter, '</i><i>') + '</i>').query('.')
        )                   AS  [A] 
    CROSS APPLY 
        [X].[nodes]('i')    AS  [X]([C]);

   RETURN;

END

要解决您的问题,我建议您这样做:

  1. 创建没有登录的数据库用户(代理用户)授予访问权限
  2. 代理用户[sysmon]创建存储过程,专用于
  3. 动态sql调用,并在头部exec作为代理用户声明。
  4. 其他,糟糕但快速的方法:

    CREATE PROCEDURE dbo.sql_dynamic
    WITH EXECUTE AS OWNER
    --- your dynamic sql call ----
    

    P.S。现在已清除,问题在于与记录集的字符串连接。

    你的第一个函数返回字符串。它可以与剩余的字符串连接。但其次,表值函数返回记录集。您不能将字符串与记录集连接。糟糕的做法。您需要根据表值函数记录集创建聚合字符串,然后将其与剩余字符串连接。

答案 1 :(得分:0)

试试这种方式

DECLARE @sql      NVARCHAR(4000)= '',
        @col_name VARCHAR(128),
        @ps_input VARCHAR(8000)= '599362,16570,568838' 

SELECT @col_name = [sysmon].[dbo].[Feedmapping]('sungard')

SET @sql = '
SELECT DISTINCT stringvalue,' + @col_name+ '
FROM   [sysmon].[dbo].[Parsestring3](@ps_input, '','')
       INNER JOIN dbname.dbo.tablename
               ON stringvalue = tablecolumn'

EXEC Sp_executesql
  @sql,
  N'@ps_input varchar(8000)', -- Declaration 
  @ps_input=@ps_input  -- To pass the input inside dynamic query