【问题标题】:SQL Server 2008 Stored Proc not returning output from dynamic querySQL Server 2008 存储过程不返回动态查询的输出
【发布时间】:2016-10-17 18:52:45
【问题描述】:

以下存储过程动态确定指定表中的列并返回所有非空列,但是存储过程返回空,尽管在自行测试动态查询时返回结果,我是否正在处理动态查询正确返回结果?

CREATE PROCEDURE [dbo].[spGetTables] 
(
    @TableName    varchar(255)
,@ParamOut    varchar(2000) OUTPUT
)
AS

declare @CommaString varchar(max)
set @CommaString = ''

Declare @col varchar(255), @cmd nvarchar(max)
declare @colName varchar(2000)
SET @colName = ''

DECLARE getinfo cursor for
SELECT c.name FROM sys.tables t JOIN sys.columns c ON t.Object_ID = c.Object_ID
WHERE t.Name = @TableName 

OPEN getinfo

FETCH NEXT FROM getinfo into @col

WHILE @@FETCH_STATUS = 0
BEGIN

    SELECT @cmd = 'IF NOT EXISTS (SELECT top 1 * FROM [' + @TableName + '] WHERE [' + @col + '] IS NULL or len([' + @col + ']) < 1) BEGIN select ''' + @col + ',''  END'

    exec sp_executesql @cmd, N'@Result varchar(max) out', @ParamOut out

    set @ParamOut = @ParamOut + @CommaString

    FETCH NEXT FROM getinfo into @col
END

PRINT 'Result: '+@ParamOut

CLOSE getinfo
DEALLOCATE getinfo
RETURN 0

【问题讨论】:

    标签: sql-server sql-server-2008 tsql stored-procedures dynamic-sql


    【解决方案1】:

    将程序更改为这个并重试:

    CREATE PROCEDURE [dbo].[spGetTables] 
    (
        @TableName    varchar(255)
    ,@ParamOut    varchar(2000) OUTPUT
    )
    AS
    
    declare @CommaString varchar(max)
    set @CommaString = ''
    
    Declare @col varchar(255), @cmd nvarchar(max)
    declare @colName varchar(2000)
    SET @colName = ''
    
    DECLARE getinfo cursor for
    SELECT c.name FROM sys.tables t JOIN sys.columns c ON t.Object_ID = c.Object_ID
    WHERE t.Name = @TableName 
    
    OPEN getinfo
    
    FETCH NEXT FROM getinfo into @col
    
    DECLARE @TempParamOut varchar(2000) = '';
    
    WHILE @@FETCH_STATUS = 0
    BEGIN
    
        SELECT @cmd = ' IF NOT EXISTS (SELECT top 1 * FROM [' + @TableName + '] WHERE [' + @col + '] IS NULL or len([' + @col + ']) < 1) BEGIN select @Result= ''' + @col + ',''  END'
    
        exec sp_executesql @cmd, N'@Result varchar(max) out', @TempParamOut out
    
        set @ParamOut = ISNULL(@ParamOut,'') + ISNULL(@TempParamOut,'') + @CommaString;
        set @TempParamOut = '';
        FETCH NEXT FROM getinfo into @col
    END
    
    
    CLOSE getinfo
    DEALLOCATE getinfo
    RETURN 0
    

    在动态T-SQL 语句中,您需要将SELECT 的值分配给变量。此外,有时这个输出值可以是NULL,但STRING + NULL 等于NULL。我添加了一个缓冲区变量@TempParamOut 用于存储中间结果。您正在使用@ParamOut 变量并在每次执行动态T-SQL 语句时覆盖其值。这就是为什么根本不执行连接的原因。

    【讨论】:

    • 除了一个小故障,它为空列重复前一个非空列,它似乎工作,谢谢@gotqn!
    • @gotqn,如果它找到 NULLS,它会保留 @TempParamOut 中的值,因此您只需在设置 @ParamOut 后将其清除.. set @ParamOut = ISNULL(@ParamOut,'') + ISNULL(@TempParamOut,'') + @CommaString; set @TempParamOut = '';
    • @ShaunGroenewald 谢谢。我已经改了。
    【解决方案2】:

    当存在基于 NULL 的附加时(使用加号(+)),我们通常会得到 NULL 作为输出。为了克服,请按照以下步骤操作,

    1. 打印动态创建的 SQL 语句并查看导致问题的字段
    2. 尝试用空字符串 ('') 替换基于 NULL 的值

    【讨论】:

      【解决方案3】:

      @gotqn 已经发现了你的错误 - 你没有为你的输出变量分配任何东西。

      但这是另一种没有游标和单源表扫描的方法:

      DECLARE
          @sql VARCHAR(MAX),
          @TableName VARCHAR(100) = 'dbo.MyTable'
      
      
      SELECT @sql = 'SELECT STUFF(''''' +
          (
              SELECT 
                  '
                  +ISNULL(
                          MIN(CASE WHEN t.' + QUOTENAME (c.name) + ' IS NOT NULL AND LEN(t.' + QUOTENAME (c.name) + ') >= 1 THEN '', ' + QUOTENAME (c.name) + ''' ELSE '''' END)
                          , '''')'
              FROM sys.columns c
              WHERE c.[object_id] = t.[object_id]
              ORDER BY c.column_id
              FOR XML PATH(''), TYPE 
           ).value('.', 'VARCHAR(MAX)') + ', 1, 1, '''') FROM ' 
           + QUOTENAME(OBJECT_SCHEMA_NAME(t.object_id)) + '.' + QUOTENAME(t.name) + ' as t'
      FROM sys.tables t
      WHERE t.object_id = object_id(@TableName, 'U')
      
      print @sql
      
      EXEC (@sql)
      
      EXEC ('select top 10 * from ' + @TableName)
      

      注意QUOTENAME 函数在这里 - 更好地使用它来代替'[' + name + ']'。当然,对象可能有不同的schema,因此按名称过滤可能不是一个安全的解决方案。

      【讨论】:

        【解决方案4】:

        离开@gotqn 的答案。

        当我运行它时,它没有正确排序结果并且返回的行太少。其中一些是因为字段中的垃圾值,例如。 “ ”,检查有点不对。

        改为 IF EXISTS 并且 NOT NULL 和 Len > 0

        ALTER PROCEDURE [dbo].[spGetTables] 
        (
            @TableName    varchar(255)
        ,@ParamOut    varchar(2000) OUTPUT
        )
        AS
        
        declare @CommaString varchar(max)
        set @CommaString = ''
        
        Declare @col varchar(255), @cmd nvarchar(max)
        declare @colName varchar(2000)
        SET @colName = ''
        
        DECLARE getinfo cursor for
        SELECT c.name FROM sys.tables t JOIN sys.columns c ON t.Object_ID = c.Object_ID
        WHERE t.Name = @TableName 
        
        OPEN getinfo
        
        FETCH NEXT FROM getinfo into @col
        
        DECLARE @TempParamOut varchar(2000) = '';
        
        WHILE @@FETCH_STATUS = 0
        BEGIN
        
            SELECT @cmd = 'IF EXISTS (SELECT top 1 * FROM [' + @TableName + '] WHERE [' + @col + '] IS NOT NULL and len(LTRIM(RTRIM(REPLACE(REPLACE(REPLACE([' + @col + '], CHAR(10), ''''), CHAR(13), ''''), CHAR(9), '''')))) > 0) BEGIN select  @Result=''' + @col + ','' END'
        
            exec sp_executesql @cmd, N'@Result varchar(max) out', @TempParamOut out
        
            set @ParamOut = ISNULL(@ParamOut,'') + ISNULL(@TempParamOut,'') + @CommaString;
            set @TempParamOut = '';
        
            FETCH NEXT FROM getinfo into @col
        END
        
        CLOSE getinfo
        DEALLOCATE getinfo
        RETURN 0
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-12-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多