在遍历游标时应检查哪些条件,以避免在表的最后一行插入错误?

时间:2018-10-06 07:56:43

标签: sql sql-server tsql stored-procedures logic

我写了一段代码,将列添加到名为 dbo.Master_Table 的表中。 该表包含当前数据库中存在的所有列。 使用了两个游标,第一个游标( TABLE_NAME )为我提供了所有游标的列表 数据库中的表,第二个光标( COLUMNS_TO_ADD )是 在(TABLE_NAME)中声明,它使我获得所有列的列表 在数据库中。

错误

  

每个表中的列名必须唯一。列名称“ 解决方案”            在表'dbo.Master_table'中指定了多次。

     

信息2705,第16级,州4,第5行            每个表中的列名必须唯一。栏名           表'dbo.Master_table'中的'Sample_Size'指定为            一次

'Resolution''Sample_Size'是最后一列 ORDINAL_POSITION 在各自的表格中。看起来像最后一个 迭代游标无法中断循环并尝试插入 他们的专栏再次。任何帮助将不胜感激。

/* Declaring the variables */

CREATE PROCEDURE DBO.SP_INSERT_MASTER

@TABLE_NAME VARCHAR(max)=NULL,
@COLUMN_NAME VARCHAR(20)=NULL,
@DATA_TYPE VARCHAR(20)=NULL,
@LENGTH INT=NULL,
@NUMERIC_PRECISION INT=NULL,
@NUMERIC_SCALE INT=NULL,
@ORDINAL_POSITION INT=NULL,
@Column varchar(max)=NULL,
@SQL varchar(max)=NULL

AS

SET NOCOUNT ON;

/* Declaring a cursor to fetch the number of tables in the DB */

DECLARE TABLE_NAME_1 CURSOR FOR

select TABLE_NAME from INFORMATION_SCHEMA.TABLES where TABLE_NAME NOT 

IN('Master','Sysssislog','XML_DB')


OPEN TABLE_NAME_1

FETCH NEXT FROM TABLE_NAME_1
INTO @TABLE_NAME

WHILE @@FETCH_STATUS=0  

--1
BEGIN


  /* Declaring a cursor to get all the columns with their 
     length,precision,scale,ordinal position */

DECLARE COLUMN_TO_ADD CURSOR FOR 
SELECT COLUMN_NAME,DATA_TYPE,CHARACTER_MAXIMUM_LENGTH,NUMERIC_PRECISION,
NUMERIC_SCALE,ORDINAL_POSITION FROM INFORMATION_SCHEMA.COLUMNS WHERE 
TABLE_NAME LIKE '%' + @TABLE_NAME + '%'

OPEN COLUMN_TO_ADD

/* Creating Temporary  table to check redundant records */
----------------------------------------------------------------------


IF EXISTS (
SELECT * FROM tempdb.sys.objects WHERE name LIKE'%#Temp2%'
           )

 --2
  BEGIN

 DROP TABLE #TEMP2
 --2
 END;


 select MAX(I.ORDINAL_POSITION) AS ORDINAL,I.TABLE_NAME INTO #TEMP2  from 
 INFORMATION_SCHEMA.COLUMNS I 
 INNER JOIN INFORMATION_SCHEMA.COLUMNS I2
 ON I.TABLE_NAME=I2.TABLE_NAME
 WHERE I.TABLE_NAME NOT IN( 'Master','Sysssislog','XML_DB') group by 
 I.TABLE_NAME


 -----------------------------------------------------------------------


 FETCH NEXT FROM COLUMN_TO_ADD
 INTO @COLUMN_NAME,@DATA_TYPE,@LENGTH,@NUMERIC_PRECISION,@NUMERIC_SCALE,
 @ORDINAL_POSITION


 WHILE @@FETCH_STATUS=0

 --3
 BEGIN


  IF @DATA_TYPE IN ('int','tinyint','bigint')
  SET @Column = (@COLUMN_NAME +' '+ @DATA_TYPE + ' '+   ''  )
  IF @DATA_TYPE IN ('varchar','nvarchar')
  SET @Column = (@COLUMN_NAME +' '+ @DATA_TYPE + ' '+ '('+  
  CAST(CASE(isnull(@LENGTH,'')) WHEN -1 THEN 1000 ELSE (isnull(@LENGTH,'')) 
  END AS varchar(max)) +')'+ ''  )
  IF @DATA_TYPE IN ('decimal','numeric')
  SET  @Column = (@COLUMN_NAME +' '+ @DATA_TYPE + ' '+  '('+ 
  cast(@NUMERIC_PRECISION as varchar(max))+','+cast(@NUMERIC_SCALE as 
  varchar(max))+')' + ''  )


   /*
   ADD New Columns TO Master Table
   */


    IF NOT EXISTS
    ( 
    SELECT 1
    FROM INFORMATION_SCHEMA.COLUMNS where TABLE_NAME LIKE '%Master_table%'  
    and COLUMN_NAME=@COLUMN_NAME
    )

   --4
   BEGIN

   Set @SQL='ALTER TABLE dbo.Master_table ADD'+ ' ' + (@Column)
   EXEC(@SQL)

   --PRINT @TABLE_NAME

   --PRINT 'Y'
   --PRINT @Column

   FETCH NEXT FROM COLUMN_TO_ADD
   INTO @COLUMN_NAME,@DATA_TYPE,@LENGTH,@NUMERIC_PRECISION,
   @NUMERIC_SCALE,@ORDINAL_POSITION

   --4
   END;

   ELSE

   IF EXISTS
    (
   select 1 from #TEMP2
   WHERE  @TABLE_NAME=TABLE_NAME and ORDINAL=@ORDINAL_POSITION
    )
   --5
   BEGIN

   PRINT @TABLE_NAME


   FETCH NEXT FROM TABLE_NAME_1
   INTO @TABLE_NAME

   --PRINT @TABLE_NAME
   --PRINT 'N'
   --PRINT @Column

   --5
   END;




  FETCH NEXT FROM COLUMN_TO_ADD
  INTO @COLUMN_NAME,@DATA_TYPE,@LENGTH,@NUMERIC_PRECISION,
  @NUMERIC_SCALE,@ORDINAL_POSITION

  --3
  END;

  FETCH NEXT FROM TABLE_NAME_1
  INTO @TABLE_NAME



  --drop #temp1

  CLOSE COLUMN_TO_ADD;
  DEALLOCATE COLUMN_TO_ADD;


  --1
  END;
  CLOSE TABLE_NAME_1;
  DEALLOCATE TABLE_NAME_1;

2 个答案:

答案 0 :(得分:0)

似乎我的查询已解决。我只是意识到我在第一个TABLE_NAME_1游标的where子句中缺少完整的表名。 (使用“ Master”代替Master_Table)。我想这就是T-sql查询试图将数据再次从dbo.Master_Table插入同一张表的原因。 进行更改后,我的查询顺利通过。感谢您的帮助。

答案 1 :(得分:0)

您对代码的一些评论:

  • 您可以使用目录视图而不是INFORMATION_SCHEMA视图,该视图提供了object_id,可用于加入视图。无论如何,您不需要2个游标。
  • 填充表#TEMP2,将表的每一列与每一列相连。您仅访问联接的一侧,因此没有必要。另外,脚本只应创建该表一次(您可以在外部WHILE循环中创建该表)。
  • 您的游标用法不一致。如果中间IF块中的条件为true,则COLUMN_TO_ADD游标将被提取两次(IF语句之后的第二次),而不检查@@FETCH_STATUS,并且如果IF语句的条件位于如果ELSE部分为true,则TABLE_NAME_1光标将移至下一条记录,而无需重新定义仍指向上一个表的列的内部光标。
  • 您的外部光标不会排除Master_table本身。
  • 您的变量被声明为存储过程的参数。
  • 您的存储过程的名称以前缀“ sp_”开头,不应用于用户定义的存储过程
  • 您不能处理所有数据类型。例如,charnchar怎么样?

我不想重新编写您的所有代码,我将留给您,只是一个提示来处理所有(或至少 more )数据类型:

SET @Column = QUOTENAME(@COLUMN_NAME) + ' ' + @DATA_TYPE + 
CASE
    WHEN  @DATA_TYPE IN ('char', 'varchar', 'nchar', 'nvarchar') THEN 
        '(' +  CASE @LENGTH WHEN -1 THEN 'max' ELSE CAST(@LENGTH AS varchar(max)) END +')'
    WHEN @DATA_TYPE IN ('decimal', 'numeric') THEN
        '(' + CAST(@NUMERIC_PRECISION as varchar(max)) + ',' + CAST(@NUMERIC_SCALE as varchar(max))+')'
    ELSE ''
END