Действительно ли я могу циклично выполниться через табличную переменную в T-SQL?

1) Это твердо
2), Это занимает время
3), очень трудно решить, что значение тестового кода

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

66
задан OMG Ponies 16 October 2009 в 14:53
поделиться

6 ответов

Добавить идентификатор вашей переменной таблицы и выполните простой цикл от 1 до @@ ROWCOUNT в INSERT-SELECT.

Попробуйте следующее:

DECLARE @RowsToProcess  int
DECLARE @CurrentRow     int
DECLARE @SelectCol1     int

DECLARE @table1 TABLE (RowID int not null primary key identity(1,1), col1 int )  
INSERT into @table1 (col1) SELECT col1 FROM table2
SET @RowsToProcess=@@ROWCOUNT

SET @CurrentRow=0
WHILE @CurrentRow<@RowsToProcess
BEGIN
    SET @CurrentRow=@CurrentRow+1
    SELECT 
        @SelectCol1=col1
        FROM @table1
        WHERE RowID=@CurrentRow

    --do your thing here--

END
95
ответ дан 24 November 2019 в 14:58
поделиться
DECLARE @table1 TABLE (
    idx int identity(1,1),
    col1 int )

DECLARE @counter int

SET @counter = 1

WHILE(@counter < SELECT MAX(idx) FROM @table1)
BEGIN
    DECLARE @colVar INT

    SELECT @colVar = col1 FROM @table1 WHERE idx = @counter

    -- Do your work here

    SET @counter = @counter + 1
END

Хотите верьте, хотите нет, но на самом деле это более эффективно и производительно, чем использование курсора.

14
ответ дан 24 November 2019 в 14:58
поделиться

Вы можете перемещаться по табличной переменной или перемещаться по ней курсором. Это то, что мы обычно называем RBAR - произносится как Reebar и означает Row-By-Agonizing-Row.

Я бы посоветовал найти НАБОРНЫЙ ответ на ваш вопрос (мы можем помочь с этим) и максимально отказаться от rbars насколько возможно.

6
ответ дан 24 November 2019 в 14:58
поделиться

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

DECLARE
  @LoopId  int
 ,@MyData  varchar(100)

DECLARE @CheckThese TABLE
 (
   LoopId  int  not null  identity(1,1)
  ,MyData  varchar(100)  not null
 )


INSERT @CheckThese (MyData)
 select MyData from MyTable
 order by DoesItMatter

SET @LoopId = @@rowcount

WHILE @LoopId > 0
 BEGIN
    SELECT @MyData = MyData
     from @CheckThese
     where LoopId = @LoopId

    --  Do whatever

    SET @LoopId = @LoopId - 1
 END

Точка зрения Раджа Мора актуальна - выполняйте циклы только в том случае, если это необходимо.

3
ответ дан 24 November 2019 в 14:58
поделиться

Я не знал о структуре WHILE.

Структура WHILE с табличной переменной, однако, похожа на использование КУРСОРА, поскольку вам все равно нужно ВЫБРАТЬ строку в переменная, основанная на строке IDENTITY, которая фактически является FETCH.

Есть ли разница между использованием WHERE и чем-то вроде следующего?

DECLARE @table1 TABLE ( col1 int )  
INSERT into @table1 SELECT col1 FROM table2

DECLARE cursor1 CURSOR  
    FOR @table1
OPEN cursor1  
FETCH NEXT FROM cursor1

Я не знаю, возможно ли это вообще. Полагаю, вам придется сделать следующее:

DECLARE cursor1 CURSOR  
    FOR SELECT col1 FROM @table1
OPEN cursor1  
FETCH NEXT FROM cursor1

Спасибо за помощь!

2
ответ дан 24 November 2019 в 14:58
поделиться

Вот еще один ответ, похожий на ответ Джастина, но не требующий идентификационных данных или совокупности, только первичный (уникальный) ключ.

declare @table1 table(dataKey int, dataCol1 varchar(20), dataCol2 datetime)
declare @dataKey int
while exists select 'x' from @table1
begin
    select top 1 @dataKey = dataKey 
    from @table1 
    order by /*whatever you want:*/ dataCol2 desc

    -- do processing

    delete from @table1 where dataKey = @dataKey
end
2
ответ дан 24 November 2019 в 14:58
поделиться
Другие вопросы по тегам:

Похожие вопросы: