Подтвердить что ты не робот

SQL - вызов хранимой процедуры для каждой записи

Я ищу способ вызова хранимой процедуры для каждой записи оператора select.

SELECT @SomeIds = (
    SELECT spro.Id 
    FROM SomeTable as spro
    INNER JOIN [Address] addr ON addr.Id = spro.Id 
    INNER JOIN City cty ON cty.CityId = addr.CityId
    WHERE cty.CityId = @CityId
)


WHILE @SomeIds  IS NOT NULL
BEGIN
    EXEC UpdateComputedFullText @SomeIds
END

Такая вещь выше, конечно, не работает, но есть ли способ сделать что-то подобное?

4b9b3361

Ответ 1

Для этого вам нужно использовать курсор.

DECLARE @oneid int -- or the appropriate type

DECLARE the_cursor CURSOR FAST_FORWARD
FOR SELECT spro.Id  
    FROM SomeTable as spro 
        INNER JOIN [Address] addr ON addr.Id = spro.Id  
        INNER JOIN City cty ON cty.CityId = addr.CityId 
    WHERE cty.CityId = @CityId

OPEN the_cursor
FETCH NEXT FROM the_cursor INTO @oneid

WHILE @@FETCH_STATUS = 0
BEGIN
    EXEC UpdateComputedFullText @oneid

    FETCH NEXT FROM the_cursor INTO @oneid
END

CLOSE the_cursor
DEALLOCATE the_cursor

Ответ 2

Удивленный никто не дал вам последний ответ. Курсоры плохие. Вы хотите переместить логику SP в табличную функцию (TVF), а затем использовать CROSS APPLY

Вот запрос, который я написал вчера (не останавливайтесь на деталях, просто посмотрите на CROSS APPLY). CROSS APPLY создает объединение таблиц. Каждый элемент этого объединения генерируется из TVF, который параметризуется в строковых элементах оператора select.

SELECT supt.hostname,supt.scriptname, COUNT(*)
FROM Event_Pagehit eph
    INNER JOIN Symboltable_urlpair supf
    ON eph.fromPagePair=supf.id
    INNER JOIN Symboltable_urlpair supt
    ON supt.id=eph.toPagePair
CROSS APPLY dbo.TDFCompanyFormationsUrlClassification(supf.hostname,supf.scriptname) as x
CROSS APPLY dbo.TDFCompanyFormationsUrlClassification(supt.hostname,supt.scriptname) as y
WHERE x.isCompanyFormations=1
AND y.isCompanyFormations=0
GROUP BY supt.hostname,supt.scriptname
ORDER BY COUNT(*) desc

Я могу использовать x и y, как если бы они были втянуты в таблицы из предложений FROM или JOIN. Если бы мне пришлось писать этот запрос без TVF, он охватывал бы пару сотен строк.

Примечание:

Если вы не можете переписать SP: вы должны иметь возможность вставлять результат хранимой процедуры в таблицу результатов из функции, связанной с таблицей. Я никогда не делал этого, и иногда у другой конструкции SQL-сервера есть предостережения. Поэтому, если кто-то не говорит иначе, я предполагаю, что это так.

Ответ 3

Поместите идентификаторы в временную переменную таблицы, а затем итерации по каждой строке: (вам не нужно использовать курсор, который будет значительно медленнее)

   Declare @Keys Table (key integer Primary Key Not Null)
   Insert @Keys(key)
   SELECT spro.Id  
   FROM SomeTable as spro 
       JOIN [Address] addr ON addr.Id = spro.Id  
       JOIN City cty ON cty.CityId = addr.CityId 
   WHERE cty.CityId = @CityId
   -- -------------------------------------------
   Declare @Key Integer
   While Exists (Select * From @Keys)
     Begin
         Select @Key = Max(Key) From @Keys
         EXEC UpdateComputedFullText @Key
         Delete @Keys Where Key = @Key
     End 

РЕДАКТИРОВАНИЕ Удаление не является медленным при использовании с предикатом фильтра, управляемым с очень узким уникальным индексом, как это. Но его можно легко избежать, просто сделав цикл следующим образом:

Declare @Key Integer Set @Key = 0
While Exists (Select * From @Keys
              Where key > @Key)
 Begin
     Select @Key = Min(Key) From @Keys
                   Where key > @KeyId
     EXEC UpdateComputedFullText @Key
     -- Delete @Keys Where Key = @Key No Longer necessary 
 End    

Ответ 4

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

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

Ответ 5

Попробуйте это без курсора

DECLARE @id int 

SELECT top 1 @id = spro.Id   
    FROM SomeTable as spro  
        INNER JOIN [Address] addr ON addr.Id = spro.Id   
        INNER JOIN City cty ON cty.CityId = addr.CityId  
    WHERE cty.CityId = @CityId
    ORDER BY spro.id

WHILE @@ROWCOUNT > 0 
BEGIN 
    EXEC UpdateComputedFullText @id 

    SELECT top 1 @id = spro.Id   
    FROM SomeTable as spro  
        INNER JOIN [Address] addr ON addr.Id = spro.Id   
        INNER JOIN City cty ON cty.CityId = addr.CityId  
    WHERE cty.CityId = @CityId 
    and spro.id > @id
    ORDER BY spro.id
END 

Ответ 6

Вам нужно будет использовать курсор: Примеры курсоров SQL Server

DECLARE @id int
DECLARE cursor_sample CURSOR FOR  
SELECT spro.Id 
FROM SomeTable as spro
    INNER JOIN [Address] addr ON addr.Id = spro.Id 
    INNER JOIN City cty ON cty.CityId = addr.CityId
WHERE cty.CityId = @CityId

OPEN cursor_sample
FETCH NEXT FROM cursor_sample INTO @id 
WHILE @@FETCH_STATUS = 0   
BEGIN  
    EXEC UpdateComputedFullText @id
    FETCH NEXT FROM cursor_sample INTO @id
END   

CLOSE cursor_sample
DEALLOCATE cursor_sample

Ответ 7

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

Вы можете поместить результаты SELECT в временную таблицу, а затем вызвать proc для выполнения массива SQL с содержимым таблицы temp. Таблица temp будет доступна для вызванного proc на основе правил определения T-SQL.

Ответ 8

Стандартное решение курсора - зло для зла. Два идентичных оператора FETCH NEXT - всего лишь кошмар для обслуживания.

лучше

...declare cursor etc.
While 1=1
 Fetch ...
 if @@FETCH_STATUS <> 0  BREAK
...
End -- While 
..Close cursor etc.

Зло иногда оправдывается. Просто попробуйте разработать подход на основе набора для отправки уведомлений с помощью sp_send_dbmail или другой хранимой процедуры.