【问题标题】:t-sql udf to return concatenated field values for one row in any given tablet-sql udf 返回任何给定表中一行的串联字段值
【发布时间】:2013-02-18 08:12:36
【问题描述】:

我正在寻找一个函数,其中传递了一个表名和一个 id 值,该过程返回一个字符串,其中包含该指定行的所有字段值。所有可以引用的表都有一个名为“Id”的字段。我发现了其他可以连接表中指定行的示例,但无法找到动态指定表的方法。以下是我在这里找到的最接近的示例:

TSQL: Values of all field in a row into one string

CREATE FUNCTION udf_GetTableValues (@TableName varchar(MAX) = '',@Id int = 0)
    RETURNS varchar(MAX)
AS
BEGIN
  DECLARE @returnVal varchar(MAX)

  SELECT @ReturnVal = ''
  SELECT @ReturnVal = @ReturnVal 
         + ' // ' 
         + T2.N.value('local-name(.)', 'nvarchar(128)')
         +': '
         + T2.N.value('.', 'nvarchar(max)')
    FROM (SELECT *
            FROM Branch 
           WHERE ID = 1
             FOR XML PATH(''), type) as T1(X)
   CROSS APPLY T1.X.nodes('/*') as T2(N)


  RETURN @ReturnVal  
END

【问题讨论】:

  • 如果没有使用 xp_cmdshell 的疯狂解决方法,您将无法在 TSQL UDF 中使用动态 SQL
  • 是的,当我尝试将命令放入带有表名的字符串并运行参数化的 sp_executesql 时,我发现了这一点,我想知道是否有另一种方法可以动态地执行此操作。否则,我能想到的唯一方法是在上述函数中使用 case 语句为每个表运行不同的查询,这 a) 看起来很丑,b) 笨拙,每次添加新表时都需要修改。

标签: sql-server tsql user-defined-functions dynamic-sql sp-executesql


【解决方案1】:

首先,您必须了解 SQL Server 拒绝在函数中允许动态 SQL 的事实。这很不幸,但这是您必须解决的限制。

这是一种在表的每一行上应用动态 SQL 逻辑的技术

  • 创建一个临时表来保存动态 SQL 的所有输入参数以及预期结果
  • 创建一个预期临时表存在的存储过程,并循环应用动态 SQL 逻辑的临时表行
  • 将要评估的数据添加到临时表中
  • 执行您的动态 SQL 过程
  • 享受您的预期结果 :-)

1) 让我们从设置一些测试数据开始。

    -- ====================================================================
    -- BEGIN: Setup test data
    -- ====================================================================
    IF OBJECT_ID('Branch', 'U') IS NOT NULL DROP TABLE Branch;
    IF OBJECT_ID('Branch2', 'U') IS NOT NULL DROP TABLE Branch2;
    GO
    CREATE TABLE Branch (
        ID      int
       ,Column1 varchar(20)
       ,Column2 varchar(20)
       ,Column3 varchar(20)
    )
    CREATE TABLE Branch2 (
        ID      int
       ,Column1 varchar(20)
       ,Column2 varchar(20)
       ,Column3 varchar(20)
    )
    SET NOCOUNT ON
    INSERT Branch SELECT 1, 'Hello', 'World', 'I write SQL'
    INSERT Branch SELECT 2, 'I like', 'it to be', 'complicated'

    INSERT Branch2 SELECT 1, 'Hello', 'World', 'I write SQL'
    INSERT Branch2 SELECT 2, 'I like', 'it to be', 'complicated'
    SET NOCOUNT OFF
    GO
    -- ====================================================================
    -- END: Setup test data
    -- ====================================================================

2) 接下来,我们将创建一个处理动态 SQL 的 proc。

    -- ====================================================================
    -- BEGIN: Proc with dynamic SQL logic
    -- ====================================================================
    IF OBJECT_ID('prcReturnTableData', 'P') IS NOT NULL DROP PROCEDURE prcReturnTableData;
    GO
    CREATE PROCEDURE prcReturnTableData 
    AS

    DECLARE @SQL                    nvarchar(MAX)
           ,@ParameterDefinitions   nvarchar(MAX)
           ,@TableName              varchar(128)
           ,@ID                     int
     SELECT @ParameterDefinitions   = '@ID int'      

    DECLARE @idx int
     SELECT @idx = MIN(idx) FROM #Result

    WHILE @idx IS NOT NULL
      BEGIN
        SELECT @TableName = TableName
              ,@ID        = ID
          FROM #Result
         WHERE idx = @idx

        SELECT @SQL = '
            DECLARE @ReturnVal varchar(MAX)

            SELECT @ReturnVal = ''''
            SELECT @ReturnVal = @ReturnVal 
                  + '' // '' 
                  + T2.N.value(''local-name(.)'', ''nvarchar(128)'')
                  + '': ''
                  + T2.N.value(''.'', ''nvarchar(max)'')
              FROM (
                    SELECT *
                      FROM ' + @TableName + ' 
                     WHERE ID = @ID
                       FOR XML PATH(''''), type
                    ) as T1(X)
             CROSS APPLY T1.X.nodes(''/*'') as T2(N)


             UPDATE #Result SET ReturnVal = @ReturnVal WHERE ID = @ID';

        EXEC sp_executeSQL @SQL, @ParameterDefinitions, @ID = @ID;

        SELECT @idx = MIN(idx) FROM #Result WHERE idx > @idx
    END
    GO
    -- ====================================================================
    -- END: Proc with dynamic SQL logic
    -- ====================================================================

3) 最后,让我们执行一下proc,得到我们想要的结果。

    -- ====================================================================
    -- BEGIN: Solution to execute dynamic SQL logic on each row of a table
    -- ====================================================================
    -- Create the temp table that the dynamic SQL proc expects
    IF OBJECT_ID('tempdb..#Result', 'U') IS NOT NULL DROP TABLE #Result;
    CREATE TABLE #Result (idx int IDENTITY(1,1), TableName varchar(128) NOT NULL, ID int NOT NULL, ReturnVal varchar(MAX) NULL);

    -- Popluate the temp table with the rows you want to evaluate
    INSERT #Result (TableName, ID)
    SELECT 'Branch', ID FROM Branch
    INSERT #Result (TableName, ID)
    SELECT 'Branch2', ID FROM Branch2

    -- Results before
    SELECT * FROM #Result

    -- Execute the dynamic SQL proc
    EXEC prcReturnTableData

    -- Results after
    SELECT * FROM #Result
    -- ====================================================================
    -- END: Solution to execute dynamic SQL logic on each row of a table
    -- ====================================================================

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-13
    • 1970-01-01
    相关资源
    最近更新 更多