sql server游标

sql server游标,sql,sql-server,tsql,cursor,Sql,Sql Server,Tsql,Cursor,我想将数据从一个表(rawdata,所有列都是VARCHAR)复制到另一个表(用相应的列格式格式化) 为了将数据从rawdata表复制到formatted表中,我使用游标来标识受影响的行。我需要在错误日志表中记录该特定行,跳过它,然后继续复制其余行 复制需要更多的时间。有没有其他方法可以做到这一点? 这是我的问题 DECLARE @EntityId Varchar(16) , @PerfId Varchar(16), @BaseId Varchar(16) ,

我想将数据从一个表(rawdata,所有列都是VARCHAR)复制到另一个表(用相应的列格式格式化)

为了将数据从
rawdata
表复制到
formatted
表中,我使用游标来标识受影响的行。我需要在错误日志表中记录该特定行,跳过它,然后继续复制其余行

复制需要更多的时间。有没有其他方法可以做到这一点? 这是我的问题

DECLARE @EntityId Varchar(16) ,
        @PerfId Varchar(16), 
        @BaseId Varchar(16) ,
        @UpdateStatus Varchar(16) 

DECLARE CursorSample CURSOR FOR 
     SELECT EntityId, PerfId, BaseId, @UpdateStatus
       FROM RawdataTable 
     --Returns 204,000 rows

OPEN CursorSample 
FETCH NEXT FROM CursorSample INTO @EntityId,@PerfId,@BaseId,@UpdateStatus

  WHILE @@FETCH_STATUS = 0 
  BEGIN 
    BEGIN TRY
    --try insertting row in formatted table

    Insert into FormattedTable
      (EntityId,PerfId,BaseId,UpdateStatus)
    Values
      (Convert(int,@EntityId),
       Convert(int,@PerfId),
       Convert(int,@BaseId),
       Convert(int,@UpdateStatus)) 
    END TRY
  BEGIN CATCH
  --capture Error EntityId in errorlog table

   Insert into ERROR_LOG
     (TableError_Message,Error_Procedure,Error_Log_Time)
   Values 
     (Error_Message()+@EntityId,’xxx’, GETDATE())

END CATCH

FETCH NEXT FROM outerCursor INTO @EntityId, @BaseId 
END 

CLOSE CursorSample 
DEALLOCATE CursorSampler –cleanup CursorSample

您可以在游标定义中放置
WHERE
子句,以便首先只选择有效记录。您可能需要创建一个函数来确定有效性,但它应该比在它们上循环更快


实际上,您可能希望创建一个包含无效记录的临时表,以便记录错误,然后仅在临时表之外的行上定义光标。

您应该能够使用INSERT INTO语句将记录直接放入格式化表中。“插入到”将比使用光标执行得更好

INSERT INTO FormattedTable
SELECT
    CONVERT(int, EntityId),
    CONVERT(int, PerfId),
    CONVERT(int, BaseId),
    CONVERT(int, UpdateStatus)
FROM RawdataTable
WHERE
    IsNumeric(EntityId) = 1
    AND IsNumeric(PerfId) = 1
    AND IsNumeric(BaseId) = 1
    AND IsNumeric(UpdateStatus) = 1
请注意,
IsNumeric
有时可以为值返回1。例如,
IsNumeric(“$e0”)
将返回1,因此您可能需要创建一个更健壮的用户定义函数来确定字符串是否为数字,具体取决于您的数据

此外,如果您需要无法移动到格式化表中的所有记录的日志,只需修改WHERE子句:

INSERT INTO ErrorLog
SELECT
    EntityId,
    PerfId,
    BaseId,
    UpdateStatus
FROM RawdataTable
WHERE
    NOT (IsNumeric(EntityId) = 1
    AND IsNumeric(PerfId) = 1
    AND IsNumeric(BaseId) = 1
    AND IsNumeric(UpdateStatus) = 1)
编辑
与其直接使用IsNumeric,不如创建一个自定义UDF,告诉您字符串是否可以转换为int。这个函数对我很有用(尽管测试有限):

插入格式化表的更新SQL如下所示:

INSERT INTO FormattedTable
SELECT
    CONVERT(int, CONVERT(NUMERIC(18,2), EntityId)),
    CONVERT(int, CONVERT(NUMERIC(18,2), PerfId)),
    CONVERT(int, CONVERT(NUMERIC(18,2), BaseId)),
    CONVERT(int, CONVERT(NUMERIC(18,2), UpdateStatus))
FROM RawdataTable
WHERE
    dbo.IsInt(EntityId) = 1
    AND dbo.IsInt(PerfId) = 1
    AND dbo.IsInt(BaseId) = 1
    AND dbo.IsInt(UpdateStatus) = 1

处理NULL可能有点奇怪(如果传入NULL,我的函数将返回0,即使INT肯定可以为NULL),但这可以根据
RawdataTable

Insert-into中的NULL值所发生的情况进行调整。Insert-into将比Cursor工作得更好。
因为游标只在电脑内存中工作,减慢了SQL Server的优化速度。我们应该避免使用游标,但(当然)有些情况下无法避免使用游标。

IsNumeric
不会返回误报。它只是回答了一个与大多数人所想的不同的问题-它没有回答“这个字符串可以转换为int吗?”-它回答了“这个字符串可以转换为一种数值类型吗?”。不幸的是,即使答案是肯定的,也没有一个函数“这个字符串可以转换为类型X吗?”(这将是有用的),或者“这个字符串可以转换为哪些数字类型?”(这可能是有用的)@Damien_不信者感谢您的反馈。我只是想指出,IsNumeric有时会为值返回1,而这些值在转换时会失败,我的措辞很糟糕。我更新了答案来说明这一点。对于Int,我们可以选择IsInt,日期、货币、浮点、十进制数据类型。@bala我认为您必须为IsInt编写类似的函数,以验证其他类型。您在这个问题上运气好吗?
INSERT INTO FormattedTable
SELECT
    CONVERT(int, CONVERT(NUMERIC(18,2), EntityId)),
    CONVERT(int, CONVERT(NUMERIC(18,2), PerfId)),
    CONVERT(int, CONVERT(NUMERIC(18,2), BaseId)),
    CONVERT(int, CONVERT(NUMERIC(18,2), UpdateStatus))
FROM RawdataTable
WHERE
    dbo.IsInt(EntityId) = 1
    AND dbo.IsInt(PerfId) = 1
    AND dbo.IsInt(BaseId) = 1
    AND dbo.IsInt(UpdateStatus) = 1