如何为存储过程返回的每个结果/记录集创建单独的表

时间:2013-12-27 21:49:30

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

我在网上发现了Sorna Kumar Muthuraj的一个非常有用的存储过程(http://goo.gl/exB1VH),它允许我搜索SQL数据库中的所有表。在大多数情况下返回的是多个记录集。我想要做的是修改我的SP,如"How do I grab multiple outputs from a stored procedure into temp table"中所述(并且不使用CLR),这样每个记录集都会写入自己的表。我读了这个stackoverflow问题的答案,因为我有一个WHILE语句,我无法弄清楚每次循环语句时如何为每个记录集创建一个单独的表或临时表。在这种情况下是否可以修改SP?我是否必须使用CLR方法?

EXEC spSQL_SearchDatabase @Tablenames = '',@SearchStr  = '%testing 123%'

存储过程:

CREATE PROCEDURE spSQL_SearchDatabase
 @Tablenames VARCHAR(500)
,@SearchStr NVARCHAR(60)
,@GenerateSQLOnly Bit = 0
AS
    SET NOCOUNT ON

    DECLARE @MatchFound BIT 

    SELECT @MatchFound = 0

DECLARE @CheckTableNames Table
(
Tablename sysname
)

DECLARE @SQLTbl TABLE
(
 Tablename      SYSNAME
,WHEREClause    VARCHAR(MAX)
,SQLStatement   VARCHAR(MAX)
,Execstatus     BIT 
)

DECLARE @sql VARCHAR(MAX)
DECLARE @tmpTblname sysname
DECLARE @ErrMsg VARCHAR(100)
DECLARE @test VARCHAR(50)

IF LTRIM(RTRIM(@Tablenames)) IN ('' ,'%')
BEGIN

    INSERT INTO @CheckTableNames
    SELECT Name
      FROM sys.tables
END
ELSE
BEGIN

    SELECT @sql = 'SELECT ''' + REPLACE(@Tablenames,',',''' UNION SELECT ''') + ''''

    INSERT INTO @CheckTableNames
    EXEC(@sql)

END

IF NOT EXISTS(SELECT 1 FROM @CheckTableNames) 
BEGIN 

    SELECT @ErrMsg = 'No tables are found in this database ' + DB_NAME() + ' for the specified filter' 
    PRINT @ErrMsg 
    RETURN 
END  

INSERT INTO @SQLTbl(Tablename, WHEREClause)
SELECT QUOTENAME(SCh.name) + '.' + QUOTENAME(ST.NAME),
        (
            SELECT '[' + SC.name + ']' + ' LIKE ''' + @SearchStr + ''' OR ' + CHAR(10)
              FROM SYS.columns SC
              JOIN SYS.types STy
                ON STy.system_type_id = SC.system_type_id
               AND STy.user_type_id =SC.user_type_id
             WHERE STY.name in ('varchar','char','nvarchar','nchar')
               AND SC.object_id = ST.object_id
             ORDER BY SC.name
            FOR XML PATH('')
        )
  FROM  SYS.tables ST
  JOIN @CheckTableNames chktbls
            ON chktbls.Tablename = ST.name 
  JOIN SYS.schemas SCh
    ON ST.schema_id = SCh.schema_id
 WHERE ST.name <> 'SearchTMP'
  GROUP BY ST.object_id, QUOTENAME(SCh.name) + '.' + QUOTENAME(ST.NAME) ;

  UPDATE @SQLTbl 
     SET SQLStatement = 'SELECT * INTO SearchTMP FROM ' + Tablename + ' WHERE ' + substring(WHEREClause,1,len(WHEREClause)-5) 

  DELETE FROM @SQLTbl
   WHERE WHEREClause IS NULL


WHILE EXISTS (SELECT 1 FROM @SQLTbl WHERE ISNULL(Execstatus ,0) = 0)
BEGIN

    SELECT TOP 1 @tmpTblname = Tablename , @sql = SQLStatement
    FROM @SQLTbl 
    WHERE ISNULL(Execstatus ,0) = 0

    IF @GenerateSQLOnly = 0
        BEGIN
        IF OBJECT_ID('SearchTMP','U') IS NOT NULL
            DROP TABLE SearchTMP

        EXEC (@sql)

        IF EXISTS(SELECT 1 FROM SearchTMP)
            BEGIN
                SELECT  Tablename=@tmpTblname, * FROM SearchTMP
                SELECT @MatchFound = 1
            END
        END
     ELSE
     BEGIN
         PRINT REPLICATE('-',100)
         PRINT @tmpTblname
         PRINT REPLICATE('-',100)
         PRINT replace(@sql,'INTO SearchTMP','')

     END

     UPDATE @SQLTbl
        SET Execstatus = 1
      WHERE Tablename = @tmpTblname

END

IF @MatchFound = 0  
BEGIN 
    SELECT @ErrMsg = 'No Matches are found in this database ' + DB_NAME() + ' for the specified filter' 
    PRINT @ErrMsg 
    RETURN 
END 

SET NOCOUNT OFF
go

这是我尝试使用WHILE子句在INTO语句中修改存储过程的地方:

IF EXISTS(SELECT 1 FROM SearchTMP)
  BEGIN
    SELECT Tablename=@tmpTblname, * INTO ResultsTMP FROM SearchTMP
    SELECT @MatchFound = 1
  END

当然它只是返回一个错误

  

每个表中的列名必须是唯一的。表'ResultsTmP'中的列名'Tablename'被多次指定

因为该表已经存在。

思想?

1 个答案:

答案 0 :(得分:1)

我不确定我是否会提出你的问题。很明显,问题在于您将所有结果存储到同一个表中。

我做了一些可能解决你问题的微调。

我没有过多地发现该程序使用“普通”tabeles作为临时表。

  1. 如果您不是所有者(或有权创建表格),则无法运行此i数据库。
  2. 您正在使用非生产数据填写事务日志。
  3. 它现在以您想要的方式创建临时表(称为## SearchResult_xxxxxx),其中xxxx是表名。

    
    create PROCEDURE spSQL_SearchDatabase
         @Tablenames VARCHAR(500)
        ,@SearchStr NVARCHAR(60)
        ,@GenerateSQLOnly Bit = 0
        AS
            SET NOCOUNT ON
    
            DECLARE @MatchFound BIT 
    
            SELECT @MatchFound = 0
    
        DECLARE @CheckTableNames Table
        (
        Tablename sysname
        )
    
        DECLARE @SQLTbl TABLE
        (
         Tablename      SYSNAME
        ,WHEREClause    VARCHAR(MAX)
        ,SQLStatement   VARCHAR(MAX)
        ,Execstatus     BIT 
        )
    
        DECLARE @sql VARCHAR(MAX)
        DECLARE @outputTableName sysname
        DECLARE @tmpTblname sysname
        DECLARE @ErrMsg VARCHAR(100)
        DECLARE @test VARCHAR(50)
    
        IF LTRIM(RTRIM(@Tablenames)) IN ('' ,'%')
        BEGIN
    
            INSERT INTO @CheckTableNames
            SELECT Name
              FROM sys.tables
        END
        ELSE
        BEGIN
    
            SELECT @sql = 'SELECT ''' + REPLACE(@Tablenames,',',''' UNION SELECT ''') + ''''
    
            INSERT INTO @CheckTableNames
            EXEC(@sql)
    
        END
    
        IF NOT EXISTS(SELECT 1 FROM @CheckTableNames) 
        BEGIN 
    
            SELECT @ErrMsg = 'No tables are found in this database ' + DB_NAME() + ' for the specified filter' 
            PRINT @ErrMsg 
            RETURN 
        END  
    
        INSERT INTO @SQLTbl(Tablename, WHEREClause)
        SELECT QUOTENAME(SCh.name) + '.' + QUOTENAME(ST.NAME),
                (
                    SELECT '[' + SC.name + ']' + ' LIKE ''' + @SearchStr + ''' OR ' + CHAR(10)
                      FROM SYS.columns SC
                      JOIN SYS.types STy
                        ON STy.system_type_id = SC.system_type_id
                       AND STy.user_type_id =SC.user_type_id
                     WHERE STY.name in ('varchar','char','nvarchar','nchar')
                       AND SC.object_id = ST.object_id
                     ORDER BY SC.name
                    FOR XML PATH('')
                )
          FROM  SYS.tables ST
          JOIN @CheckTableNames chktbls
                    ON chktbls.Tablename = ST.name 
          JOIN SYS.schemas SCh
            ON ST.schema_id = SCh.schema_id
         WHERE ST.name  'SearchTMP'
          GROUP BY ST.object_id, QUOTENAME(SCh.name) + '.' + QUOTENAME(ST.NAME) ;
    
          UPDATE @SQLTbl 
             SET SQLStatement = 'SELECT * INTO ##SearchTMP FROM ' + Tablename + ' WHERE ' + substring(WHEREClause,1,len(WHEREClause)-5) 
    
          DELETE FROM @SQLTbl
           WHERE WHEREClause IS NULL
    
    
        WHILE EXISTS (SELECT 1 FROM @SQLTbl WHERE ISNULL(Execstatus ,0) = 0)
        BEGIN
    
            SELECT TOP 1 @tmpTblname = Tablename , @sql = SQLStatement
            FROM @SQLTbl 
            WHERE ISNULL(Execstatus ,0) = 0
    
            IF @GenerateSQLOnly = 0
                BEGIN
                IF OBJECT_ID('tempdb..##SearchTMP','U') IS NOT NULL
                    DROP TABLE ##SearchTMP
    
                EXEC (@sql)
    
                IF EXISTS(SELECT 1 FROM ##SearchTMP)
                    BEGIN
                        set @outputTableName = '[##SearchResult_'+ 
                            replace(replace(@tmpTblname,'[',''),']','') +']'
                        print 'Created ' + @outputTableName
                        IF OBJECT_ID('tempdb..'+@outputTableName,'U') IS NOT NULL
                            exec ('DROP TABLE tempdb.'+@outputTableName)
                        exec ('SELECT  Tablename='''+@tmpTblname+''', * into ' +@outputTableName + ' FROM ##SearchTMP')
    
                        SELECT @MatchFound = 1
                    END
                END
             ELSE
             BEGIN
                 PRINT REPLICATE('-',100)
                 PRINT @tmpTblname
                 PRINT REPLICATE('-',100)
                 PRINT replace(@sql,'INTO ##SearchTMP','')
    
             END
    
             UPDATE @SQLTbl
                SET Execstatus = 1
              WHERE Tablename = @tmpTblname
    
        END
    
        IF @MatchFound = 0  
        BEGIN 
            SELECT @ErrMsg = 'No Matches are found in this database ' + DB_NAME() + ' for the specified filter' 
            PRINT @ErrMsg 
            RETURN 
        END 
    
        IF OBJECT_ID('tempdb..##SearchTMP','U') IS NOT NULL
            DROP TABLE ##SearchTMP
    
        SET NOCOUNT OFF
        go