Курсор T-SQL и обновление - PullRequest
       16

Курсор T-SQL и обновление

1 голос
/ 28 октября 2010

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

Если значение существует, я хотел бы увеличить столбец значений в этой другой таблице.Если нет, я хотел бы вставить туда новую строку со значением, установленным в 1.

Я проверяю "если существует" по:

IF (SELECT COUNT(*) FROM otherTabe WHERE... > 1)
   BEGIN
      ...
   END
ELSE
   BEGIN
      ...
   END

Я не знаю, как получить эту строкукоторый был найден и обновил значение.Я не хочу делать другой выбор.

Как я могу сделать это эффективно?

Я предполагаю, что описанный выше метод проверки не подходит для этого случая.

Ответы [ 5 ]

4 голосов
/ 29 октября 2010

В зависимости от размера ваших данных и фактического состояния у вас есть два основных подхода:

1) использование MERGE

MERGE TOP (...) INTO table1
USING table2 ON table1.column = table2.column
WHEN MATCHED
 THEN UPDATE SET table1.counter += 1
WHEN NOT MATCHED SOURCE
 THEN INSERT (...) VALUES (...);

*Требуется 1009 *, потому что когда вы делаете огромное обновление, подобное этому (вы упоминаете, что таблица «большая», большая - относительная, но давайте предположим, что действительно большие строки + 100 ММ), вам придется пакетировать обновления, в противном случае вы будетепереполните журнал транзакций одной гигантской транзакцией.

2) используйте курсор, как вы пытаетесь.Ваш исходный вопрос может быть легко решен, просто всегда обновите и затем проверьте количество обновленных строк:

UPDATE table 
  SET column += 1
WHERE ...;
IF @@ROW_COUNT = 0
BEGIN
   -- no match, insert new value 
   INSERT INTO (...) VALUES (...);
END

Обратите внимание, что этот подход опасен, хотя из-за условий гонки: нет ничегочтобы предотвратить одновременную вставку значения другим потоком, чтобы вы могли получить либо дубликаты, либо ошибку нарушения ограничения (предпочтительно последний ...).

2 голосов
/ 29 октября 2010

Я думаю вам лучше использовать представление для этого - тогда оно всегда актуально, нет риска ошибочного подсчета двойного / тройного / и т. Д.:

CREATE VIEW vw_value_count AS
  SELECT st.value,
         COUNT(*) AS numValue
    FROM SOME_TABLE st
GROUP BY st.value

Но если вы все еще хотите использовать подход INSERT / UPDATE:

IF EXISTS(SELECT NULL
            FROM SOMETABLE WHERE ... > 1) 
BEGIN
   UPDATE TABLE
      SET count = count + 1
    WHERE value = @value
END
ELSE
BEGIN
   INSERT INTO TABLE
     (value, count)
   VALUES
     (@value, 1)
END
2 голосов
/ 29 октября 2010

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

Update OtherTable
  Set ColumnToIncrease = ColumnToIncrease + 1
FROM CurrentTable Where ColumnToCheckValue is not null

Insert Into OtherTable (ColumnToIncrease, Field1, Field2,...)
SELECT 
  1,
  ?
  ?
FROM CurrentTable Where ColumnToCheckValue is not null
2 голосов
/ 29 октября 2010

Без образца, я думаю, это лучшее, что я могу сделать. Итог: вам не нужен курсор. UPDATE, где совпадение существует (INNER JOIN) и INSERT, где нет совпадения.

UPDATE otherTable
SET IncrementingColumn = IncrementingColumn + 1
FROM thisTable INNER JOIN otherTable ON thisTable.ID = otherTable.ID

INSERT INTO otherTable
(
   ID
   , IncrementingColumn
)
SELECT ID, 1
FROM thisTable
WHERE NOT EXISTS (SELECT *
                  FROM otherTable
                  WHERE thisTable.ID = otherTable.ID)
1 голос
/ 28 октября 2010

Как насчет оператора Update с внутренним объединением для выполнения +1 и вставки выбранных строк, которые не существуют в первой таблице.

Укажите схему таблиц и столбцы, которые вы хотите проверить и обновить, чтобы я могпомощь.

С уважением.

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