SQL Server - 动态表名称作为变量

时间:2018-01-16 15:49:14

标签: sql-server stored-procedures

我一直在尝试使用动态名称创建表时遇到问题。我一直收到这些错误:

  

消息102,级别15,状态1,过程SP_SearchTables,第159行
  '@tablename'附近的语法不正确。

     

消息1087,等级15,状态2,程序SP_SearchTables,第165行
  必须声明表变量“@tablename”。

     

Msg 1087,Level 15,State 2,Procedure SP_SearchTables,Line 171
  必须声明表变量“@tablename”。

正如您在存储过程中看到的那样,在此更改之前,我有SearchTMP而不是@tablename,但我不想给出固定名称,我想提供动态名称。考虑到这一点,我给了一个名字和一些随机数字,但它一直给我以前显示的错误,你能帮助我吗?

我将发布我的存储过程。

ALTER PROCEDURE [dbo].[SearchTables] 
    @SearchStr NVARCHAR(60),
    @GenerateSQLOnly BIT = 0, 
    @SchemaNames VARCHAR(500) ='%' 
AS 
    SET NOCOUNT ON 

    DECLARE @MatchFound BIT 

    SELECT @MatchFound = 0 

    DECLARE @CheckTableNames TABLE (Schemaname sysname, Tablename sysname) 
    DECLARE @SearchStringTbl TABLE (SearchString VARCHAR(500)) 

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

    DECLARE @SQL VARCHAR(MAX) 
    DECLARE @TableParamSQL VARCHAR(MAX) 
    DECLARE @SchemaParamSQL VARCHAR(MAX) 
    DECLARE @TblSQL VARCHAR(MAX) 
    DECLARE @tmpTblname sysname 
    DECLARE @ErrMsg VARCHAR(100) 

    IF LTRIM(RTRIM(@SchemaNames)) ='' 
    BEGIN 
        SELECT @SchemaNames = '%' 
    END 

    IF CHARINDEX(',',@SchemaNames) > 0  
        SELECT @SchemaParamSQL = 'SELECT ''' + REPLACE(@SchemaNames,',','''as SchemaName UNION SELECT ''') + '''' 
    ELSE 
        SELECT @SchemaParamSQL = 'SELECT ''' + @SchemaNames + ''' as SchemaName ' 

    SELECT @TblSQL = 'SELECT SCh.NAME,T.NAME 
                      FROM SYS.TABLES T 
                      JOIN SYS.SCHEMAS SCh ON SCh.SCHEMA_ID = T.SCHEMA_ID 
                      INNER JOIN [DynaForms].[dbo].[Enums_Tables] et ON (et.Id = T.NAME COLLATE Latin1_General_CI_AS)  '

    INSERT INTO @CheckTableNames (Schemaname, Tablename) 
        EXEC (@TblSQL) 

    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 

    IF LTRIM(RTRIM(@SearchStr)) ='' 
    BEGIN 
        SELECT @ErrMsg = 'Please specify the search string in @SearchStr Parameter' 
        PRINT @ErrMsg 
        RETURN 
    END 
    ELSE 
    BEGIN  
        SELECT @SearchStr = REPLACE(@SearchStr,',,,',',#DOUBLECOMMA#') 
        SELECT @SearchStr = REPLACE(@SearchStr,',,','#DOUBLECOMMA#') 

        SELECT @SearchStr = REPLACE(@SearchStr,'''','''''') 

        SELECT @SQL = 'SELECT ''' + REPLACE(@SearchStr,',','''as SearchString UNION SELECT ''') + '''' 

        INSERT INTO @SearchStringTbl (SearchString) 
            EXEC(@SQL) 

        UPDATE @SearchStringTbl 
        SET SearchString = REPLACE(SearchString ,'#DOUBLECOMMA#',',') 
    END 

    INSERT INTO @SQLTbl (Tablename, WHEREClause) 
        SELECT 
            QUOTENAME(SCh.name) + '.' + QUOTENAME(ST.NAME), 
            (SELECT '[' + SC.Name + ']' + ' LIKE ''' + REPLACE(SearchSTR.SearchString,'''','''''') + ''' 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 
             CROSS JOIN @SearchStringTbl SearchSTR 
             WHERE STY.name IN ('varchar', 'char', 'nvarchar', 'nchar', 'text') 
               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 
                            AND Sch.name = chktbls.Schemaname 
        WHERE 
            ST.name <> 'SearchTMP' 
        GROUP BY 
            ST.object_id, QUOTENAME(SCh.name) + '.' +  QUOTENAME(ST.NAME) ; 

    DECLARE @numbers VARCHAR(MAX)
    SET @numbers = CONVERT(NUMERIC(12, 0), RAND() * 899999999999) + 100000000000

    DECLARE @tablename VARCHAR(MAX)
    SET @tablename = 'SearchTMP' + @numbers

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


    DELETE FROM @SQLTbl 
    WHERE WHEREClause IS NULL 

    DECLARE @output TABLE (Id VARCHAR(50), Name VARCHAR(100)) 

    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('@tablename','U') IS NOT NULL 
                 DROP TABLE @tablename

            EXEC (@SQL) 

            IF EXISTS(SELECT 1 FROM @tablename) 
            BEGIN 
                --SELECT parsename(@tmpTblname,1) FROM SearchTMP 
                SELECT @MatchFound = 1 

                INSERT INTO @output (Id, Name)
                    SELECT * 
                    FROM [DynaForms].[dbo].[Enums_Tables] 
                    WHERE id IN (SELECT parsename(@tmpTblname, 1) FROM @tablename)
             END 
         END 
         ELSE 
         BEGIN 
             PRINT REPLICATE('-',100) 
             PRINT @tmpTblname 
             PRINT REPLICATE('-',100) 
             PRINT replace(@SQL,'INTO @tablename','') 
         END 

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

    SELECT * FROM @output
    --Select * from @SQLTbl

    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 

修改

我更改了我的存储过程以获得动态sql,但它给了我这个错误:

Msg 214, Level 16, State 2, Procedure sp_executesql, Line 1
Procedure expects parameter '@statement' of type 'ntext/nchar/nvarchar'.

我认为这个问题出在我的子查询中,但是我看不到它的工作原理,请你帮忙吗?子查询在这里:

DECLARE @SQLSUBQUERY VARCHAR(max);

SELECT @SQLSUBQUERY = 'SELECT * FROM [DynaForms].[dbo].[Enums_Tables] ';
SELECT @SQLSUBQUERY = @SQLSUBQUERY + 'WHERE id IN (SELECT  parsename(@tmpTblname,1) FROM @tablename)';

INSERT INTO @output (Id, Name)
    EXEC sp_executesql @SQLSUBQUERY

完整代码:

ALTER PROCEDURE [dbo].[SP_SearchTables] 
    @SearchStr NVARCHAR(60),
    @GenerateSQLOnly Bit = 0,
    @SchemaNames VARCHAR(500) ='%' 
AS 
    SET NOCOUNT ON 

    DECLARE @MatchFound BIT 
    SELECT @MatchFound = 0 

    DECLARE @CheckTableNames TABLE (Schemaname sysname, Tablename sysname) 

    DECLARE @SearchStringTbl TABLE (SearchString VARCHAR(500)) 

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

    DECLARE @SQL VARCHAR(MAX) 
    DECLARE @TableParamSQL VARCHAR(MAX) 
    DECLARE @SchemaParamSQL VARCHAR(MAX) 
    DECLARE @TblSQL VARCHAR(MAX) 
    DECLARE @tmpTblname sysname 
    DECLARE @ErrMsg VARCHAR(100) 

    IF LTRIM(RTRIM(@SchemaNames)) ='' 
    BEGIN 
        SELECT @SchemaNames = '%' 
    END 

    IF CHARINDEX(',',@SchemaNames) > 0  
        SELECT @SchemaParamSQL = 'SELECT ''' + REPLACE(@SchemaNames,',','''as SchemaName UNION SELECT ''') + '''' 
    ELSE 
        SELECT @SchemaParamSQL = 'SELECT ''' + @SchemaNames + ''' as SchemaName ' 

    SELECT @TblSQL = 'SELECT SCh.NAME,T.NAME 
              FROM SYS.TABLES T 
              JOIN SYS.SCHEMAS SCh 
              ON SCh.SCHEMA_ID = T.SCHEMA_ID 
              INNER JOIN [DynaForms].[dbo].[Enums_Tables] et on 
                 (et.Id = T.NAME COLLATE Latin1_General_CI_AS)  '

    INSERT INTO @CheckTableNames (Schemaname, Tablename) 
        EXEC(@TblSQL) 

    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 

IF LTRIM(RTRIM(@SearchStr)) ='' 
BEGIN 

    SELECT @ErrMsg = 'Please specify the search string in @SearchStr Parameter' 
    PRINT @ErrMsg 
    RETURN 
END 
ELSE 
BEGIN  
    SELECT @SearchStr = REPLACE(@SearchStr,',,,',',#DOUBLECOMMA#') 
    SELECT @SearchStr = REPLACE(@SearchStr,',,','#DOUBLECOMMA#') 

    SELECT @SearchStr = REPLACE(@SearchStr,'''','''''') 

    SELECT @SQL = 'SELECT ''' + REPLACE(@SearchStr,',','''as SearchString UNION SELECT ''') + '''' 



    INSERT INTO @SearchStringTbl 
    (SearchString) 
    EXEC(@SQL) 

    UPDATE @SearchStringTbl 
       SET SearchString = REPLACE(SearchString ,'#DOUBLECOMMA#',',') 
END 

INSERT INTO @SQLTbl (Tablename, WHEREClause) 
    SELECT 
        QUOTENAME(SCh.name) + '.' + QUOTENAME(ST.NAME), 
        (SELECT '[' + SC.Name + ']' + ' LIKE ''' + REPLACE(SearchSTR.SearchString,'''','''''') + ''' 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 
         CROSS JOIN @SearchStringTbl SearchSTR 
         WHERE 
             STY.name in ('varchar','char','nvarchar','nchar','text') 
             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 
   AND Sch.name        = chktbls.Schemaname 
 WHERE ST.name <> 'SearchTMP' 
  GROUP BY ST.object_id, QUOTENAME(SCh.name) + '.' +  QUOTENAME(ST.NAME) ; 

declare @numbers varchar(MAx)
set @numbers = convert(numeric(12,0),rand() * 899999999999) + 100000000000
declare @tablename varchar(MAX) 
set @tablename = 'SearchTMP' + @numbers

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


  DELETE FROM @SQLTbl 
   WHERE WHEREClause IS NULL 

 DECLARE @output TABLE (Id VARCHAR(50), Name VARCHAR(100)) 

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 

            DECLARE @SQLs NVARCHAR(MAX)
            SELECT @SQLs = 'DROP TABLE dbo.' + QUOTENAME(@tablename) + '';

        IF OBJECT_ID(''+@tablename+'','U') IS NOT NULL 
          EXEC sp_executesql @SQLs;


         EXEC (@SQL) 


        --IF EXISTS(SELECT 1 FROM @tablename) 
        BEGIN 
            --SELECT parsename(@tmpTblname,1) FROM SearchTMP 
            SELECT @MatchFound = 1 

            DECLARE @SQLSUBQUERY VARCHAR(max);
            SELECT @SQLSUBQUERY = 'SELECT * FROM [DynaForms].[dbo].[Enums_Tables] ';
            SELECT @SQLSUBQUERY = @SQLSUBQUERY + 'WHERE id IN (SELECT  parsename(@tmpTblname,1) FROM @tablename)';

            INSERT INTO @output (Id, Name)
            EXEC sp_executesql @SQLSUBQUERY
            --Select * from [DynaForms].[dbo].[Enums_Tables] where id in (SELECT parsename(@tmpTblname,1) FROM @tablename)
        END 

     END 
     ELSE 
     BEGIN 
         PRINT REPLICATE('-',100) 
         PRINT @tmpTblname 
         PRINT REPLICATE('-',100) 
         PRINT replace(@SQL,'INTO @tablename','') 
     END 

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

END 

SELECT * FROM @output
--Select * from @SQLTbl


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 

1 个答案:

答案 0 :(得分:1)

至少存在以下错误:

  

如果OBJECT_ID('@ tablename','U')不是空

这是错误的,因为检查名称为@tablename

的表
  

IF EXISTS(SELECT 1 FROM @tablename)

这会产生你所得到的错误。

DROP TABLE不接受变量,使用动态sql到你的drop