T-SQL: Цитирование через массив известных значений
Здесь мой сценарий:
Скажем, у меня есть хранимая процедура, в которой мне нужно вызвать другую хранимую процедуру в наборе определенных идентификаторов; есть ли способ сделать это?
то есть. вместо того, чтобы это делать:
exec p_MyInnerProcedure 4
exec p_MyInnerProcedure 7
exec p_MyInnerProcedure 12
exec p_MyInnerProcedure 22
exec p_MyInnerProcedure 19
Выполнение чего-то подобного:
*magic where I specify my list contains 4,7,12,22,19*
DECLARE my_cursor CURSOR FAST_FORWARD FOR
*magic select*
OPEN my_cursor
FETCH NEXT FROM my_cursor INTO @MyId
WHILE @@FETCH_STATUS = 0
BEGIN
exec p_MyInnerProcedure @MyId
FETCH NEXT FROM my_cursor INTO @MyId
END
Моя основная цель - просто ремонтировать (легко удалить/добавить id в качестве бизнес-изменений), имея возможность отображать все идентификаторы в одной строке... Производительность не должна быть такой большой проблемой
Ответы
Ответ 1
declare @ids table(idx int identity(1,1), id int)
insert into @ids (id)
select 4 union
select 7 union
select 12 union
select 22 union
select 19
declare @i int
declare @cnt int
select @i = min(idx) - 1, @cnt = max(idx) from @ids
while @i < @cnt
begin
select @i = @i + 1
declare @id = select id from @ids where idx = @i
exec p_MyInnerProcedure @id
end
Ответ 2
В этом сценарии я создаю переменную таблицы для хранения идентификаторов.
Declare @Ids Table (id integer primary Key not null)
Insert @Ids(id) values (4),(7),(12),(22),(19)
- (или вызвать другую функцию с табличной оценкой для создания этой таблицы)
Затем цикл, основанный на строках в этой таблице
Declare @Id Integer
While exists (Select * From @Ids)
Begin
Select @Id = Min(id) from @Ids
exec p_MyInnerProcedure @Id
Delete from @Ids Where id = @Id
End
или...
Declare @Id Integer = 0 -- assuming all Ids are > 0
While exists (Select * From @Ids
where id > @Id)
Begin
Select @Id = Min(id)
from @Ids Where id > @Id
exec p_MyInnerProcedure @Id
End
Любой из вышеперечисленных подходов намного быстрее, чем курсор (объявляется против обычных таблиц пользователей). Табличные переменные имеют плохую репутацию, потому что при неправильном использовании (для очень широких таблиц с большим количеством строк) они не работают. Но если вы используете их только для хранения значения ключа или целого числа из 4 байтов, с индексом (как в этом случае), они очень быстры.
Ответ 3
используйте статическую переменную курсора и функцию разделения:
declare @comma_delimited_list varchar(4000)
set @comma_delimited_list = '4,7,12,22,19'
declare @cursor cursor
set @cursor = cursor static for
select convert(int, Value) as Id from dbo.Split(@comma_delimited_list) a
declare @id int
open @cursor
while 1=1 begin
fetch next from @cursor into @id
if @@fetch_status <> 0 break
....do something....
end
-- not strictly necessary w/ cursor variables since they will go out of scope like a normal var
close @cursor
deallocate @cursor
Курсоры имеют плохое повторение, так как параметры по умолчанию, объявленные для пользовательских таблиц, могут привести к большим накладным расходам.
Но в этом случае накладные расходы довольно минимальны, меньше, чем любые другие методы здесь. STATIC говорит SQL Server материализовать результаты в базе данных tempdb, а затем выполнить итерацию. Для таких небольших списков это оптимальное решение.
Ответ 4
Обычно я использую следующий подход
DECLARE @calls TABLE (
id INT IDENTITY(1,1)
,parameter INT
)
INSERT INTO @calls
select parameter from some_table where some_condition -- here you populate your parameters
declare @i int
declare @n int
declare @myId int
select @i = min(id), @n = max(id) from @calls
while @i <= @n
begin
select
@myId = parameter
from
@calls
where id = @i
EXECUTE p_MyInnerProcedure @myId
set @i = @i+1
end
Ответ 5
Вы можете попробовать следующее:
declare @list varchar(MAX), @i int
select @i=0, @list ='4,7,12,22,19,'
while( @i < LEN(@list))
begin
declare @item varchar(MAX)
SELECT @item = SUBSTRING(@list, @i,CHARINDEX(',',@list,@i)[email protected])
select @item
--do your stuff here with @item
exec p_MyInnerProcedure @item
set @i = CHARINDEX(',',@list,@i)+1
if(@i = 0) set @i = LEN(@list)
end
Ответ 6
CREATE TABLE #ListOfIDs (IDValue INT)
DECLARE @IDs VARCHAR(50), @ID VARCHAR(5)
SET @IDs = @OriginalListOfIDs + ','
WHILE LEN(@IDs) > 1
BEGIN
SET @ID = SUBSTRING(@IDs, 0, CHARINDEX(',', @IDs));
INSERT INTO #ListOfIDs (IDValue) VALUES(@ID);
SET @IDs = REPLACE(',' + @IDs, ',' + @ID + ',', '')
END
SELECT *
FROM #ListOfIDs
Ответ 7
Это может заставить вас идти. Из вопроса не ясно, что именно копировать и куда.
SET "MOSTRECENT=unknown"
FOR /F "delims=" %%d IN ('DIR /B /A:D /O:D "%COMPUTERNAME%*"') DO (
SET "MOSTRECENT=%%~fd"
)
ECHO The most recent backup is "%MOSTRECENT%"
IF EXIST "MOSTRECENT" (COPY ...