Inilah skenario saya:
Katakanlah saya memiliki prosedur tersimpan di mana saya perlu memanggil prosedur tersimpan lainnya pada satu set id tertentu; apakah ada cara untuk melakukan ini?
yaitu, alih-alih perlu melakukan ini:
exec p_MyInnerProcedure 4
exec p_MyInnerProcedure 7
exec p_MyInnerProcedure 12
exec p_MyInnerProcedure 22
exec p_MyInnerProcedure 19
Melakukan sesuatu seperti ini:
*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
Tujuan utama saya di sini hanyalah kemudahan perawatan (mudah untuk menghapus / menambahkan id saat bisnis berubah), dapat mencantumkan semua Id dalam satu baris ... Kinerja seharusnya tidak menjadi masalah besar
sql
sql-server
tsql
John
sumber
sumber
Jawaban:
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
sumber
Apa yang saya lakukan dalam skenario ini adalah membuat variabel tabel untuk menampung Id.
Declare @Ids Table (id integer primary Key not null) Insert @Ids(id) values (4),(7),(12),(22),(19)
- (atau panggil fungsi nilai tabel lain untuk menghasilkan tabel ini)
Kemudian putar berdasarkan baris dalam tabel ini
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
atau...
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
Salah satu dari pendekatan di atas jauh lebih cepat daripada kursor (dideklarasikan terhadap Tabel Pengguna biasa). Variabel nilai tabel memiliki reputasi yang buruk karena ketika digunakan secara tidak benar, (untuk tabel yang sangat lebar dengan jumlah baris yang besar) mereka tidak berkinerja baik. Tetapi jika Anda menggunakannya hanya untuk menyimpan nilai kunci atau integer 4 byte, dengan indeks (seperti dalam kasus ini) mereka sangat cepat.
sumber
gunakan variabel kursor statis dan fungsi split :
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
Kursor memiliki reputasi yang buruk karena opsi default saat dideklarasikan terhadap tabel pengguna dapat menghasilkan banyak overhead.
Tetapi dalam hal ini biaya overhead cukup minimal, kurang dari metode lain di sini. STATIC memberitahu SQL Server untuk mewujudkan hasil dalam tempdb dan kemudian mengulanginya. Untuk daftar kecil seperti ini, ini adalah solusi optimal.
sumber
Anda dapat mencoba seperti di bawah ini:
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)-@i) 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
sumber
@list ='4,7,12,22,19' + ','
- jadi sangat jelas bahwa daftar harus diakhiri dengan koma (tidak akan bekerja tanpanya!).Saya biasanya menggunakan pendekatan berikut
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
sumber
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
sumber
Buat koneksi ke DB Anda menggunakan bahasa pemrograman prosedural (di sini Python), dan lakukan perulangan di sana. Dengan cara ini Anda juga dapat melakukan loop rumit.
# make a connection to your db import pyodbc conn = pyodbc.connect(''' Driver={ODBC Driver 13 for SQL Server}; Server=serverName; Database=DBname; UID=userName; PWD=password; ''') cursor = conn.cursor() # run sql code for id in [4, 7, 12, 22, 19]: cursor.execute(''' exec p_MyInnerProcedure {} '''.format(id))
sumber