【问题标题】:How to get a value from func/sp to a case statement using dynamic SQL?如何使用动态 SQL 从 func/sp 获取值到 case 语句?
【发布时间】:2014-12-05 00:03:05
【问题描述】:

希望有人可以帮助我解决一些问题。本质上,我正在尝试获取数据库中所有字段的粗略大小,因为我想对其进行一些数学运算,以猜测应用压缩技术后的大小。

我可以通过查看数据类型并使用行数来获取它占用的字节数来对大多数字段执行此操作。然而,在类似 varchar(max) 字段的情况下,这并不容易,所以我决定通过获取列内的平均长度并乘以行数来解决这个问题。但我遇到了一个障碍,我将在下面描述。

我有以下存储过程(我也尝试了一个函数,但你不能从函数调用动态 SQL)。

CREATE PROCEDURE dbo.getFieldSize(@column varchar(255), @table varchar(255), @ret decimal(15,7) OUTPUT) AS BEGIN DECLARE @lengthSQL varchar(50) /SET @lengthSQL = 'SELECT @ret = AVG(DATALENGTH(' + @column + ')) FROM [' + @table +']'/ SET @lengthSQL = 'SELECT @ret = AVG(DATALENGTH(' + @column + ')) FROM ' + @table exec sp_executesql @lengthSQL RETURN @ret END GO

然后我用...调用它

SELECT b.TABLE_SCHEMA as 'Schema', CASE WHEN DATA_TYPE IN ('nvarchar') AND CHARACTER_MAXIMUM_LENGTH <> -1 AND c.distinctItems <> 0 AND c.totalCount <> 0 THEN exec('select max(len(' + b.TABLE_CATALOG + ' + '.' + ' + b.COLUMN_NAME + '))') FROM .... 以上基本上只是检查以确保它是一个 varchar(max) 字段并在列中包含一些值。然后我尝试执行 SP 并传递我需要平均长度的列名和表名,但出现以下错误。

消息 156,级别 15,状态 1,行 57 关键字“exec”附近的语法不正确。

我了解到您不能从函数调用动态 SQL,也不能从 CASE 语句调用 SP。所以在这一点上,它似乎是一个陷阱 22,我无法使用 SQL 做我需要的事情。谁能想到任何解决方法,或者我对此不走运?

【问题讨论】:

    标签: sql-server-2008 function stored-procedures dynamic-sql case-statement


    【解决方案1】:

    实际上,您可以在标量 UDF 中执行动态 SQL,它只需要是 SQLCLR UDF ;-)。但这使用进程内/内部连接(即SqlConnection("Context Connection = true;");)相当简单。意思是,程序集可以设置为安全。

    此外,对象/列/索引名称都是 NVARCHAR。并且对象(如果不是其他对象)被声明为sysname,这是NVARCHAR(128) 的别名。仅供参考。

    所以,类似于以下内容(我已经测试过并且确实有效):

    [Microsoft.SqlServer.Server.SqlFunction(Name = "GetAvgBytes",
        IsDeterministic = false, IsPrecise = true, DataAccess = DataAccessKind.Read)]
    public static SqlInt32 GetAvgBytes([SqlFacet(MaxSize = 128)] SqlString TableName,
        [SqlFacet(MaxSize = 128)] SqlString ColumnName)
    {
        int _AvgBytes = -1;
        SqlConnection _Connection = new SqlConnection("Context Connection = true;");
        SqlCommand _Command = _Connection.CreateCommand();
        _Command.CommandType = CommandType.Text;
        _Command.CommandText = "SELECT @AvgBytes = AVG(DATALENGTH(" + ColumnName.Value
                            + ")) FROM " + TableName.Value + " WITH (NOLOCK);";
    
        SqlParameter _Param = new SqlParameter("@AvgBytes", DbType.Int32);
        _Param.Direction = ParameterDirection.Output;
        _Command.Parameters.Add(_Param);
    
        try
        {
            _Connection.Open();
    
            _Command.ExecuteNonQuery();
    
            _AvgBytes = (int)_Param.Value;
        }
        finally
        {
            _Connection.Close();
        }
    
        return _AvgBytes;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-03-28
      • 1970-01-01
      • 2020-08-06
      • 1970-01-01
      • 1970-01-01
      • 2015-04-21
      • 1970-01-01
      • 2010-10-04
      相关资源
      最近更新 更多