2013-09-16 5 views
13

Возможно ли каким-то образом выполнить некоторый код для каждой строки выбора без использования курсора?TSQL - выполнить код для каждой строки выбора

В моем случае: У меня есть временная таблица для хранения некоторых данных для сценария complexe. В конце я хочу вывести некоторую информацию этой таблицы (ограниченную некоторыми условиями) на вывод.

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

print '...' 

для генерации вывода.

Там должна быть более простой способ сделать такие вещи ...

редактировать:

create table #tmpAttributes(AttributeId uniqueidentifier, Value float, ValueString nvarchar(max), ActionId uniqueidentifier) 

insert into #tmpAttributes (AttributeId, Value, ValueString, ActionId) 
    select ID,..... -- in this select i'm doing some value conversions, if conversion is not possible i'm using -1 

insert into ActionAttribute (ActionDefinitionID, Discriminator, ID, ReferredActionID, ValueDate, ValueListID, ValueMoney, ValueString, ValueUserID) 
    select @defId, 'ActionAttributeMoneyEntity', NEWID(), ActionId, null, null, Value, null, null from #tmpAttributes 

-- afterwards there is this cursor where I'm printint all rows where Value = -1 
+2

Информация не достаточна.Чего вы на самом деле пытаетесь достичь? Если вы дадите нам полный сценарий, вы можете обнаружить, что существует полностью установленный способ делать то, что вам нужно. – gvee

+0

Почему бы вам просто не добавить один дополнительный столбец идентификатора в «temp table», который вы уже создали, и цикл для каждой строки. –

+0

Если вы просто хотите распечатать эту информацию «в конце», почему вам нужен курсор? – DrCopyPaste

ответ

19

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

declare @id int, @stuff varchar(20) 
declare @tmp table 
(
    id int not null 
, stuff varchar(20) 

    primary key(id) 
) 

insert @tmp 
select id, stuff from mastertable 
where condition1 > condition2 

select top 1 @id=id, @stuff=stuff from @tmp 

while (@@rowcount > 0) 
begin 
    print @stuff 
    delete from @tmp where [email protected] 
    select top 1 @id=id, @stuff=stuff from @tmp 
end 

Вы по-прежнему перемещаетесь по каждой строке, но избегаете курсора. Поскольку вы используете таблицу var вместо курсора, вы избегаете блокировки таблицы, но это не обязательно лучший подход. Вы можете обрабатывать строки за строкой множеством возможных способов, таких как добавление «обработанного столбца» или нумерация всех выбранных строк 1..n и итерация в соответствии с номером rownumber

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

Теперь запись CLR-proc может быть более гибкой, так как у вас намного более богатая модель программирования, и для каждой строки результирующий набор в процедуре CLR. Выполнение вызова базы данных из процедуры CLR для каждой строки, вызываемой вызовом базы данных из каждой строки в TSQL

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

declare @msg varchar(max) 
select @msg = '' 

select msg = @msg + stuff 
from mastertable where condition1 > condition2 

print @msg 

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


Я сказал, что использование temp var позволяет избежать блокировки таблиц. Это не совсем так, поскольку SQL-сервер записывает temp vars в таблицу в tempdb. Я действительно имел в виду, что вы избегаете блокировки производственной таблицы, и, поскольку вы гарантированно являетесь единственным пользователем этой таблицы, вы не конкурируете за одновременный доступ.

Я также не пытался оптимизировать это. Например, внутренний цикл может отслеживать идентификатор, а условие where становится id> @id (вам также нужен первичный ключ, определенный на id). Поскольку временная таблица не обновляется во время каждой итерации цикла, я бы ожидал, что она будет быстрее.

+0

Еще петля, но без использования «тяжелого» курсора. Спасибо! –

8

Я думаю, что вам нужно предоставить более подробную информацию, но вы могли бы искать что-то вроде:

declare @msg varchar(max)=''; 

select @msg = @msg + 'Output line: ' + ColumnA + ' -- ' + 'ColumnB' + char(13)+char(10) 
from #temp 
where ... 
; 

print @msg; 
+0

Итак, для каждой строки значение переменной будет расширено ... хорошая идея! –

+0

Обязательно добавьте «OPTION (MAXDOP 1)» для предотвращения параллелизма, что даст неожиданные результаты. – gjvdkamp

Смежные вопросы