Let's mengatakan saya memiliki sederhana berikut ini tabel variabel:
declare @databases table
(
DatabaseID int,
Name varchar(15),
Server varchar(15)
)
-- insert a bunch rows into @databases
Menyatakan dan menggunakan kursor saya satu-satunya pilihan jika saya ingin iterate melalui baris? Apakah ada cara lain?
Pertama-tama anda harus benar-benar yakin anda perlu untuk iterate melalui setiap baris - mengatur berdasarkan operasi akan tampil lebih cepat di setiap hal yang dapat saya pikirkan dan biasanya akan menggunakan sederhana kode.
Tergantung pada data anda mungkin mungkin untuk loop hanya menggunakan pernyataan select seperti yang ditunjukkan di bawah ini:
Declare @Id int
While (Select Count(*) From ATable Where Processed = 0) > 0
Begin
Select Top 1 @Id = Id From ATable Where Processed = 0
--Do some processing here
Update ATable Set Processed = 1 Where Id = @Id
End
Alternatif lain adalah dengan menggunakan tabel sementara:
Select *
Into #Temp
From ATable
Declare @Id int
While (Select Count(*) From #Temp) > 0
Begin
Select Top 1 @Id = Id From #Temp
--Do some processing here
Delete #Temp Where Id = @Id
End
Pilihan yang harus anda pilih benar-benar tergantung pada struktur dan volume data anda.
Catatan: Jika anda menggunakan SQL Server anda akan lebih baik dilayani menggunakan:
WHILE EXISTS(SELECT * FROM #Temp)
Menggunakan COUNT
akan harus menyentuh setiap baris dalam tabel, ADA
hanya perlu sentuhan yang pertama (lihat Josef's jawaban di bawah ini).
Hanya sebuah catatan, jika anda menggunakan SQL Server (2008 dan di atas), contoh-contoh yang telah:
While (Select Count(*) From #Temp) > 0
Akan lebih baik dilayani dengan
While EXISTS(SELECT * From #Temp)
Count akan harus menyentuh setiap baris dalam tabel, ADA
hanya perlu sentuhan yang pertama.
Ini adalah bagaimana saya melakukannya:
declare @RowNum int, @CustId nchar(5), @Name1 nchar(25)
select @CustId=MAX(USERID) FROM UserIDs --start with the highest ID
Select @RowNum = Count(*) From UserIDs --get total number of records
WHILE @RowNum > 0 --loop until no more records
BEGIN
select @Name1 = username1 from UserIDs where USERID= @CustID --get other info from that row
print cast(@RowNum as char(12)) + ' ' + @CustId + ' ' + @Name1 --do whatever
select top 1 @CustId=USERID from UserIDs where USERID < @CustID order by USERID desc--get the next one
set @RowNum = @RowNum - 1 --decrease count
END
Tidak ada Kursor, sementara tidak ada meja, tidak ada kolom tambahan. USERID kolom harus unik integer, sebagai Primary key.
Tentukan tabel temp seperti ini -
declare @databases table
(
RowID int not null identity(1,1) primary key,
DatabaseID int,
Name varchar(15),
Server varchar(15)
)
-- insert a bunch rows into @databases
Kemudian melakukan ini -
declare @i int
select @i = min(RowID) from @databases
declare @max int
select @max = max(RowID) from @databases
while @i <= @max begin
select DatabaseID, Name, Server from @database where RowID = @i --do some stuff
set @i = @i + 1
end
Berikut adalah cara yang akan saya lakukan:
Select Identity(int, 1,1) AS PK, DatabaseID
Into #T
From @databases
Declare @maxPK int;Select @maxPK = MAX(PK) From #T
Declare @pk int;Set @pk = 1
While @pk <= @maxPK
Begin
-- Get one record
Select DatabaseID, Name, Server
From @databases
Where DatabaseID = (Select DatabaseID From #T Where PK = @pk)
--Do some processing here
--
Select @pk = @pk + 1
End
[Edit] Karena saya mungkin melewatkan kata-kata "variabel" ketika saya pertama kali membaca pertanyaan, berikut adalah sebuah diperbarui respon...
declare @databases table
(
PK int IDENTITY(1,1),
DatabaseID int,
Name varchar(15),
Server varchar(15)
)
-- insert a bunch rows into @databases
--/*
INSERT INTO @databases (DatabaseID, Name, Server) SELECT 1,'MainDB', 'MyServer'
INSERT INTO @databases (DatabaseID, Name, Server) SELECT 1,'MyDB', 'MyServer2'
--*/
Declare @maxPK int;Select @maxPK = MAX(PK) From @databases
Declare @pk int;Set @pk = 1
While @pk <= @maxPK
Begin
/* Get one record (you can read the values into some variables) */
Select DatabaseID, Name, Server
From @databases
Where PK = @pk
/* Do some processing here */
/* ... */
Select @pk = @pk + 1
End
Jika anda tidak memiliki pilihan selain untuk pergi ke baris demi baris menciptakan FAST_FORWARD kursor. Itu akan menjadi secepat membangun sebuah while loop dan lebih mudah untuk mempertahankan dalam jangka panjang.
FAST_FORWARD Menentukan FORWARD_ONLY, READ_ONLY kursor dengan optimasi kinerja diaktifkan. FAST_FORWARD tidak dapat ditentukan jika SCROLL atau FOR_UPDATE juga ditentukan.
Pendekatan lain tanpa harus mengubah skema atau menggunakan temp tabel:
DECLARE @rowCount int = 0
,@currentRow int = 1
,@databaseID int
,@name varchar(15)
,@server varchar(15);
SELECT @rowCount = COUNT(*)
FROM @databases;
WHILE (@currentRow <= @rowCount)
BEGIN
SELECT TOP 1
@databaseID = rt.[DatabaseID]
,@name = rt.[Name]
,@server = rt.[Server]
FROM (
SELECT ROW_NUMBER() OVER (
ORDER BY t.[DatabaseID], t.[Name], t.[Server]
) AS [RowNumber]
,t.[DatabaseID]
,t.[Name]
,t.[Server]
FROM @databases t
) rt
WHERE rt.[RowNumber] = @currentRow;
EXEC [your_stored_procedure] @databaseID, @name, @server;
SET @currentRow = @currentRow + 1;
END
-- [PO_RollBackOnReject] 'FININV10532'
alter procedure PO_RollBackOnReject
@CaseID nvarchar(100)
AS
Begin
SELECT *
INTO #tmpTable
FROM PO_InvoiceItems where CaseID = @CaseID
Declare @Id int
Declare @PO_No int
Declare @Current_Balance Money
While (Select ROW_NUMBER() OVER(ORDER BY PO_LineNo DESC) From #tmpTable) > 0
Begin
Select Top 1 @Id = PO_LineNo, @Current_Balance = Current_Balance,
@PO_No = PO_No
From #Temp
update PO_Details
Set Current_Balance = Current_Balance + @Current_Balance,
Previous_App_Amount= Previous_App_Amount + @Current_Balance,
Is_Processed = 0
Where PO_LineNumber = @Id
AND PO_No = @PO_No
update PO_InvoiceItems
Set IsVisible = 0,
Is_Processed= 0
,Is_InProgress = 0 ,
Is_Active = 0
Where PO_LineNo = @Id
AND PO_No = @PO_No
End
End
Ringan, tanpa harus membuat tabel tambahan, jika anda memiliki integer ID
di meja
Declare @id int = 0, @anything nvarchar(max)
WHILE(1=1) BEGIN
Select Top 1 @anything=[Anything],@id=@id+1 FROM Table WHERE ID>@id
if(@@ROWCOUNT=0) break;
--Process @anything
END
It's mungkin untuk menggunakan kursor untuk melakukan hal ini:
membuat fungsi [dbo].[f_teste_loop]() kembali @tabela meja ( cod int, nome varchar(10) ) sebagai begin
insert into @tabela values (1, 'verde');
insert into @tabela values (2, 'amarelo');
insert into @tabela values (3, 'azul');
insert into @tabela values (4, 'branco');
return;
end
membuat prosedur [dbo].[sp_teste_loop] sebagai begin
DECLARE @cod int, @nome varchar(10);
DECLARE curLoop CURSOR STATIC LOCAL
FOR
SELECT
cod
,nome
FROM
dbo.f_teste_loop();
OPEN curLoop;
FETCH NEXT FROM curLoop
INTO @cod, @nome;
WHILE (@@FETCH_STATUS = 0)
BEGIN
PRINT @nome;
FETCH NEXT FROM curLoop
INTO @cod, @nome;
END
CLOSE curLoop;
DEALLOCATE curLoop;
end
Ini akan bekerja pada versi SQL SERVER 2012.
declare @Rowcount int
select @Rowcount=count(*) from AddressTable;
while( @Rowcount>0)
begin
select @Rowcount=@Rowcount-1;
SELECT * FROM AddressTable order by AddressId desc OFFSET @Rowcount ROWS FETCH NEXT 1 ROWS ONLY;
end
Saya lebih suka menggunakan Offset Mengambil jika anda memiliki ID unik anda dapat mengurutkan meja anda oleh:
DECLARE @TableVariable (ID int, Name varchar(50));
DECLARE @RecordCount int;
SELECT @RecordCount = COUNT(*) FROM @TableVariable;
WHILE @RecordCount > 0
BEGIN
SELECT ID, Name FROM @TableVariable ORDER BY ID OFFSET @RecordCount - 1 FETCH NEXT 1 ROW;
SET @RecordCount = @RecordCount - 1;
END
Cara ini saya don't perlu untuk menambahkan bidang ke tabel atau penggunaan fungsi jendela.
Aku benar-benar tidak mengerti mengapa anda akan perlu resor untuk menggunakan ditakuti kursor
.
Tapi di sini adalah pilihan lain jika anda menggunakan versi SQL Server 2005/2008
Menggunakan Rekursi
declare @databases table
(
DatabaseID int,
Name varchar(15),
Server varchar(15)
)
--; Insert records into @databases...
--; Recurse through @databases
;with DBs as (
select * from @databases where DatabaseID = 1
union all
select A.* from @databases A
inner join DBs B on A.DatabaseID = B.DatabaseID + 1
)
select * from DBs
I'm akan memberikan set berbasis solusi.
insert @databases (DatabaseID, Name, Server)
select DatabaseID, Name, Server
From ... (Use whatever query you would have used in the loop or cursor)
Ini jauh lebih cepat daripada setiap perulangan techique dan lebih mudah untuk menulis dan memelihara.
Berikut ini's solusi saya, yang membuat penggunaan loop tak terbatas, ISTIRAHAT
pernyataan, dan @@ROWCOUNT
fungsi. Tidak ada kursor atau tabel sementara yang diperlukan, dan aku hanya perlu menulis satu query untuk mendapatkan baris berikutnya dalam @database
tabel:
declare @databases table
(
DatabaseID int,
[Name] varchar(15),
[Server] varchar(15)
);
-- Populate the [@databases] table with test data.
insert into @databases (DatabaseID, [Name], [Server])
select X.DatabaseID, X.[Name], X.[Server]
from (values
(1, 'Roger', 'ServerA'),
(5, 'Suzy', 'ServerB'),
(8675309, 'Jenny', 'TommyTutone')
) X (DatabaseID, [Name], [Server])
-- Create an infinite loop & ensure that a break condition is reached in the loop code.
declare @databaseId int;
while (1=1)
begin
-- Get the next database ID.
select top(1) @databaseId = DatabaseId
from @databases
where DatabaseId > isnull(@databaseId, 0);
-- If no rows were found by the preceding SQL query, you're done; exit the WHILE loop.
if (@@ROWCOUNT = 0) break;
-- Otherwise, do whatever you need to do with the current [@databases] table row here.
print 'Processing @databaseId #' + cast(@databaseId as varchar(50));
end
Saya setuju dengan posting sebelumnya yang ditetapkan berdasarkan operasi biasanya akan tampil lebih baik, tapi jika anda perlu untuk iterate atas baris-baris berikut's pendekatan yang saya ambil:
MENYATAKAN @pangkalan data TABEL ( DatabaseID int, Nama varchar(15), Server varchar(15), menyatu BIT DEFAULT 0 )
-- insert sekelompok baris ke @database
MENYATAKAN @DBID INT
PILIH TOP 1 @DBID = DatabaseID dari @database mana menyatu = 0
SEMENTARA @@ROWCOUNT <> 0 dan @DBID TIDAK NULL BEGIN
--Update catatan untuk "digunakan"
UPDATE @database SET menyatu = 1 DIMANA DatabaseID = @DBID
Pendekatan ini hanya membutuhkan satu variabel dan tidak menghapus baris dari @database. Saya tahu ada banyak jawaban di sini, tapi aku don't melihat salah satu yang menggunakan MENIT anda berikutnya ID seperti ini.
DECLARE @databases TABLE
(
DatabaseID int,
Name varchar(15),
Server varchar(15)
)
-- insert a bunch rows into @databases
DECLARE @CurrID INT
SELECT @CurrID = MIN(DatabaseID)
FROM @databases
WHILE @CurrID IS NOT NULL
BEGIN
-- Do stuff for @CurrID
SELECT @CurrID = MIN(DatabaseID)
FROM @databases
WHERE DatabaseID > @CurrID
END
Langkah 1: di Bawah ini pilih pernyataan yang menciptakan tabel temp dengan nomor baris untuk setiap record.
select eno,ename,eaddress,mobno int,row_number() over(order by eno desc) as rno into #tmp_sri from emp
Step2:Mendeklarasi variabel yang dibutuhkan
DECLARE @ROWNUMBER INT
DECLARE @ename varchar(100)
Step3: Mengambil baris total count dari tabel temp
SELECT @ROWNUMBER = COUNT(*) FROM #tmp_sri
declare @rno int
Step4: Loop tabel temp berdasarkan unik nomor baris buat di temp
while @rownumber>0
begin
set @rno=@rownumber
select @ename=ename from #tmp_sri where rno=@rno **// You can take columns data from here as many as you want**
set @rownumber=@rownumber-1
print @ename **// instead of printing, you can write insert, update, delete statements**
end
Ini adalah kode yang saya gunakan 2008 R2. Ini kode yang saya gunakan adalah untuk membangun indeks pada field-field kunci (SSNO & EMPR_NO) n semua cerita
if object_ID('tempdb..#a')is not NULL drop table #a
select 'IF EXISTS (SELECT name FROM sysindexes WHERE name ='+CHAR(39)+''+'IDX_'+COLUMN_NAME+'_'+SUBSTRING(table_name,5,len(table_name)-3)+char(39)+')'
+' begin DROP INDEX [IDX_'+COLUMN_NAME+'_'+SUBSTRING(table_name,5,len(table_name)-3)+'] ON '+table_schema+'.'+table_name+' END Create index IDX_'+COLUMN_NAME+'_'+SUBSTRING(table_name,5,len(table_name)-3)+ ' on '+ table_schema+'.'+table_name+' ('+COLUMN_NAME+') ' 'Field'
,ROW_NUMBER() over (order by table_NAMe) as 'ROWNMBR'
into #a
from INFORMATION_SCHEMA.COLUMNS
where (COLUMN_NAME like '%_SSNO_%' or COLUMN_NAME like'%_EMPR_NO_')
and TABLE_SCHEMA='dbo'
declare @loopcntr int
declare @ROW int
declare @String nvarchar(1000)
set @loopcntr=(select count(*) from #a)
set @ROW=1
while (@ROW <= @loopcntr)
begin
select top 1 @String=a.Field
from #A a
where a.ROWNMBR = @ROW
execute sp_executesql @String
set @ROW = @ROW + 1
end