Таблица Переменная внутри курсора, странное поведение – SQL Server

Я заметил странную вещь внутри хранимой процедуры с помощью select on table variables. Он всегда возвращает значение (на последующих итерациях), которое было выбрано на первой итерации курсора. Вот пример кода, подтверждающий это.

DECLARE @id AS INT; DECLARE @outid AS INT; DECLARE sub_cursor CURSOR FAST_FORWARD FOR SELECT [TestColumn] FROM testtable1; OPEN sub_cursor; FETCH NEXT FROM sub_cursor INTO @id; WHILE @@FETCH_STATUS = 0 BEGIN DECLARE @Log TABLE (LogId BIGINT NOT NULL); PRINT 'id: ' + CONVERT (VARCHAR (10), @id); INSERT INTO Testtable2 (TestColumn) OUTPUT inserted.[TestColumn] INTO @Log VALUES (@id); IF @@ERROR = 0 BEGIN SELECT TOP 1 @outid = LogId FROM @Log; PRINT 'Outid: ' + CONVERT (VARCHAR (10), @outid); INSERT INTO [dbo].[TestTable3] ([TestColumn]) VALUES (@outid); END FETCH NEXT FROM sub_cursor INTO @id; END CLOSE sub_cursor; DEALLOCATE sub_cursor; 

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

 SELECT TOP 1 @outid = LogId FROM @Log; 

что сделало бы это так

 SELECT @outid = LogId FROM @Log; 

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

Обновление : у меня есть решение обойти странное поведение здесь. В качестве решения я объявлял таблицу вверху цикла и удалял все строки в начале цикла.

С этим кодом есть несколько вещей.

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

Что может смутить вас в @Log таблицы @Log это то, что SQL Server не использует те же правила определения переменных и жизненных @Log , что и C ++ или другие стандартные языки программирования. Даже когда вы объявляете свою переменную таблицы в блоке курсора, вы получаете только одну таблицу @Log которая затем живет для оставшейся части пакета и которая получает в нее несколько строк.

В результате ваше использование TOP 1 не имеет особого смысла, поскольку предложение ORDER BY предусматривает какого-либо детерминированного порядка на столе. Без этого вы получаете любой заказ SQL Server, который вам подходит, который в этом случае выглядит как порядок вставки, предоставляя вам первый вставленный элемент этой таблицы журналов каждый раз, когда вы запускаете SELECT .

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

Давайте будем гением компьютера.