SQL Server курсор - PullRequest
       9

SQL Server курсор

2 голосов
/ 03 мая 2011

Я хочу скопировать данные из одной таблицы (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

Ответы [ 3 ]

4 голосов
/ 03 мая 2011

Вы должны просто иметь возможность использовать инструкцию INSERT INTO, чтобы поместить записи прямо в отформатированную таблицу. 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 для значений , которые затем завершатся ошибкой при CONVERT . Например, 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. Эта функция работала для меня (хотя и с ограниченным тестированием):

CREATE FUNCTION IsInt(@value VARCHAR(50))
RETURNS bit
AS
BEGIN
    DECLARE @number AS INT
    DECLARE @numeric AS NUMERIC(18,2)
    SET @number = 0
    IF IsNumeric(@value) = 1
      BEGIN
        SET @numeric = CONVERT(NUMERIC(18,2), @value)
        IF @numeric BETWEEN -2147483648 AND 2147483647
            SET @number = CONVERT(INT, @numeric)
      END

    RETURN @number
END
GO

Обновленный 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 (моя функция будет возвращать 0, если передан NULL, даже если INT может быть нулевым), но это можно отрегулировать в зависимости от того, что должно происходить со значениями NULL в RawdataTable.

2 голосов
/ 03 мая 2011

Вы можете поместить предложение WHERE в определение курсора, чтобы в первую очередь выбирались только действительные записи.Вам может потребоваться создать функцию для определения достоверности, но это должно быть быстрее, чем их циклическое повторение.

На самом деле, вы можете создать временную таблицу из неверных записей, чтобывы можете регистрировать ошибки, а затем определять курсор только для строк, которых нет во временной таблице.

0 голосов
/ 10 ноября 2015

Вставить в будет работать намного лучше, чем курсор.Так как Cursor работают исключительно в памяти вашего ПК и замедляют оптимизацию SQL Server.Мы должны избегать использования курсоров, но (конечно) существуют ситуации, когда нельзя избежать использования курсора.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...