Почему бы не использовать курсор???
Я должен не согласиться со многими другими ответами, которые вы найдете здесь, в StackOverflow. Как правило, вы увидите, что люди говорят о курсорах самые разные плохие вещи... и они правы, когда мы говорим о традиционных таблицах... единственная проблема в том, что ваш вопрос касается табличной переменной, которая вы используете внутри хранимой процедуры.
Ваша первая точка принятия решения всегда должна заключаться в том, чтобы увидеть, можете ли вы выполнить операцию на основе набора, а не итерацию (построчную обработку). Базы данных оптимизированы для первого. Ответ, который я даю здесь, предназначен для тех, кто решил, что они никак не могут использовать подход, основанный на наборах, и целью итерации является табличная переменная.
Ваша табличная переменная похожа на коллекцию на языке программирования. Это частная структура в памяти. Нет абсолютно никаких проблем с повторением этого в стиле ForEach, когда вы находитесь внутри хранимой процедуры. Если ваш сценарий действительно требует построчной обработки, то курсор, безусловно, подходит в вашем случае. Я действительно не понимаю, почему бы и нет.
Давайте рассмотрим пример, основанный на вашем сценарии. Сначала мы определяем тип таблицы:
CREATE TYPE [IntListType] AS TABLE
( [T] INT );
GO
Затем мы определяем хранимую процедуру, которая использует эту таблицу в качестве входных данных:
CREATE PROCEDURE [myTest]
(
@IntListInput IntListType READONLY
)
AS
BEGIN
SET NOCOUNT ON;
DECLARE @myInt INT;
DECLARE intListCursor CURSOR LOCAL FAST_FORWARD
FOR
SELECT [T]
FROM @IntListInput;
OPEN intListCursor;
-- Initial fetch attempt
FETCH NEXT FROM intListCursor INTO @myInt;
WHILE @@FETCH_STATUS = 0
BEGIN
-- Here we do some kind of action that requires us to
-- process the table variable row-by-row. This example simply
-- uses a PRINT statement as that action (not a very good
-- example).
PRINT 'Int var is : ' + CONVERT(VARCHAR(max),@myInt);
-- Attempt to fetch next row from cursor
FETCH NEXT FROM intListCursor INTO @myInt;
END;
CLOSE intListCursor;
DEALLOCATE intListCursor;
END;
GO
Итак, да, я использую курсор для итерации.
Обратите внимание, что я использую ключевые слова LOCAL
и FAST_FORWARD
просто для того, чтобы оптимизатору было очень ясно (явно), что я не собираюсь обновлять свой курсор, и я буду прокручивать только вперед, и я буду получать к нему доступ только внутри процедуры.
Я тестировал это так:
DECLARE @IntList IntListType;
-- Put some random data into our list
INSERT INTO @IntList VALUES (33);
INSERT INTO @IntList VALUES (777);
INSERT INTO @IntList VALUES (845);
INSERT INTO @IntList VALUES (71);
EXEC myTest @IntList;
GO
person
peterh
schedule
27.06.2013