0

テーブル名と列名のパラメーターに基づいて、コンマ区切りの値のリストを返す関数を作成しようとしています。

アイデアは、動的 SQL ステートメントをオンザフライで構築し、結果を返すことでした。executeただし、関数内でステートメントを実行できないという問題に遭遇しました。これが私が持っていたものです:

ALTER FUNCTION fn_HearingAttendeesToCSV (@TableName varchar(100), 
                                         @ColumnName varchar(100))
RETURNS VARCHAR(MAX)
AS
BEGIN
declare @sql varchar(max)

select @sql = 
'DECLARE @listStr VARCHAR(MAX)
    SELECT @listStr = COALESCE(@listStr + '', '' ,'''') + ' 
          + @ColumnName + ' FROM ' + @TableName + ' RETURN @listStr '

Exec (@sql)
END
GO

私は間違った道を進んでいると確信しています。誰かが問題を回避する方法を提案できますかexecute? または、これを行うより良い方法はありますか?

4

4 に答える 4

3

関数 - ピリオドではこれを行うことはできません。関数は動的 SQL を実行できないため、任意のテーブル/列名 (非決定論的) を使用すると、SQL Server 関数に直面します。

于 2011-03-27T20:15:35.543 に答える
2

T-SQLを介してこれを実行できるとは思いませんが、C#で記述されたUDFを介して同じことを実行することは絶対に可能です。コードは次のとおりです。

using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;

public partial class UserDefinedFunctions {
   [Microsoft.SqlServer.Server.SqlFunction(DataAccess = DataAccessKind.Read)]
   public static SqlString fn_HearingAttendeesToCSV(SqlString tableName, SqlString columnName) {
      System.Text.StringBuilder result = null;
      using (var cnn = new SqlConnection("context connection=true")) {
         var cmd = new SqlCommand();
         cmd.CommandText = String.Format("select [{0}] from [{1}]", SqlEscape(columnName.Value), SqlEscape(tableName.Value));
         cmd.Connection = cnn;

         cnn.Open();
         using (var rdr = cmd.ExecuteReader()) {
            while (rdr.Read()) {
               if (result == null) {
                  result = new System.Text.StringBuilder();
               }
               else {
                  result.Append(",");
               }
               result.Append(CsvEscape(rdr[0]));
            }
         }
         cnn.Close();
      }

      if (result == null) {
         return SqlString.Null;
      }
      else {
         return result.ToString();
      }
   }

   private static string SqlEscape(string s) {
      s = s ?? "";
      return s.Replace("[", "[[").Replace("]", "]]");
   }

   private static string CsvEscape(object o) {
      var s = o == null ? "" : o.ToString();
      return "\"" + s.Replace("\"", "\"\"") + "\"";
   }
};

CLR UDFを使用するには、次のようにサーバーでCLRUDFが有効になっていることを確認する必要があります。

exec sp_configure 'clr enabled', 1
RECONFIGURE

また、SQL 2005では4.0アセンブリが許可されていないため、古いバージョンの.NET Framework(2.0は私がテストしたものです)にコンパイルする必要があります。

UDFはC#で記述されていますが、これまでと同じ方法でT-SQLを介してUDFにアクセスできます。

select fn_HearingAttendeesToCSV('table', 'column')

'dbo'以外のスキーマをサポートする必要がある場合、または純粋なCSVが必要ない場合は、ニーズに合わせて変更しますが、99%の方法でそこに到達するはずです。つまり、あなたがDBAであるか、CLRを有効にするのに十分な仲間であると仮定します。

于 2011-03-27T21:48:28.360 に答える
2

こんにちは、関数については正しいと思いますが、SP を出力パラメーターと共に使用してこれを行うことができます。

このコードを確認してください:

create proc DynCsv 
    @table  varchar(100),
    @column varchar(100),
    @csv    varchar(8000) output
as 
    declare
            @sql    nvarchar(4000),
            @parms  nvarchar(100)

    -- setup parms 
    select  @csv = '',          
            @sql = '
    select top 10 @csv = @csv +'','' + CAST(' + @column + ' as varchar)
    from ' + @table + ' option(maxdop 1)',
            @parms = '@csv varchar(8000) output'

    -- execute dynamic
    exec sp_executesql 
            @sql,
            @parms,
            @csv = @csv output

    -- loose first comma    
    set @csv = substring(@csv, 2, 8000)

次のコードで呼び出すことができます。

declare @csv varchar(8000)
exec dynCsv 'tObj', 'ObjId', @csv output
print @csv

幸運を、

GJ

于 2011-03-27T20:56:04.397 に答える
1

これを関数で行うことはできませんが、PROCEDURE で行うことはできます。動的 SQL ステートメントを作成するために、これを何度も行いました。

それが行く方法です。

于 2011-03-27T20:55:29.977 に答える