Pendahuluan
Tulisan ini merupakan bagian dari beberapa tips tentang penggunaan cursor yang salah. Saya juga akan memberikan solusi bagaimana cara menulis ulang cursor sebagai simple SQL statement.
Kasus
Salah satu penggunaan cursor yang salah yang sering saya temui adalah menggunakan cursor untuk melakukan update terhadap suatu table menggunakan summary data dari table lainnya. Misalnya Anda punya table ProductEndOfDay dan table WarehouseTransaction. Table ProductEndOfDay merupakan table yang mencatat berapa quantity on hand untuk setiap product pada akhir transaksi setiap harinya. Sedangkan table WarehouseTransaction merupakan table yang mencatat setiap transaksi di warehouse. Anda ingin melakukan batch process untuk mencatat berapa posisi on hand setiap product setiap harinya.
Logika pengerjaannya adalah Anda akan mencatat berapa jumlah transaksi untuk setiap product di hari berjalan, dan kemudian akan menambahkan nilai tersebut dengan nilai on hand di hari kemarin, dan kemudian menyimpan hasilnya sebagai row baru di table ProductEndOfDay.
Misalkan kita akan menggunakan struktur table seperti dibawah ini:
CREATE
TABLE ProductEndOfDay
(
ProductEndOfDayId Int
Identity
Primary
Key,
ProductId Int,
EndOfDayDate DateTime,
QuantityOnHand Int
)
GO
CREATE
TABLE WarehouseTransaction
(
TransactionId Int
Identity
Primary
Key,
ProductId Int,
TransactionDate DateTime,
TransactionType Char(3),
TransactionQuantity Int
)
TransactionType misalnya kita definsikan valuenya BUY untuk product yang diterima dan SLS untuk product yang dikeluarkan dari warehouse untuk penjualan. Nilai semua transaksi sesuai dengan jenis transaksinya, positif untuk BUY dan negatif untuk SLS.
Pada saat Anda melakukan update ke table ProductEndOfDay, Anda misalnya menggunakan cursor seperti code dibawah ini:
DECLARE @ProductId Int,
@Quantity Int
DECLARE crEndOfDay CURSOR
FOR
SELECT ProductId,
SUM(TransactionQuantity)
FROM WarehouseTransaction
WHERE CONVERT(Varchar(10), TransactionDate, 112)
=
CONVERT(Varchar(10),
GETDATE(), 112)
GROUP
BY ProductId
OPEN crEndOfDay
FETCH
NEXT
FROM crEndOfDay INTO @ProductId, @Quantity
WHILE
@@FETCH_STATUS
= 0
BEGIN
INSERT
INTO ProductEndOfDay(ProductId, EndOfDayDate, QuantityOnHand)
SELECT ProductId,
DATEADD(dd, 1,
GETDATE())
As EndOfDayDate, QuantityOnHand + @Quantity
FROM ProductEndOfDay
WHERE CONVERT(Varchar(10), EndOfDayDate, 112)
=
CONVERT(Varchar(10),
DATEADD(dd, 1,
GETDATE()), 112)
AND
ProductId = @ProductId
FETCH
NEXT
FROM crEndOfDay INTO @ProductId, @Quantity
END
CLOSE crEndOfDay
DEALLOCATE crEndOfDay
Solusi
Sekarang mari kita tulis ulang code diatas tanpa menggunakan cursor. Inti dari proses diatas adalah mencari berapa total transaksi pada hari ini, kemudian mencari berapa QuantityOnHand di hari kemarin, dan menjumlahkan total transaksi hari ini dengan QuantityOnHand kemarin, kemudian disimpan ke table ProductEndOfDay
INSERT
INTO ProductEndOfDay(ProductId, EndOfDayDate, QuantityOnHand)
SELECT A.ProductId, B.EndOfDayDate, A.TodayQuantity + B.QuantityOnHand
FROM
(
SELECT ProductId,
SUM(TransactionQuantity)
As TodayQuantity
FROM WarehouseTransaction
WHERE CONVERT(Varchar(10), TransactionDate, 112)
=
CONVERT(Varchar(10),
GETDATE(), 112)
GROUP
BY ProductId
)
As A JOIN
(
SELECT ProductId,
DATEADD(dd, 1,
GETDATE())
As EndOfDayDate, QuantityOnHand
FROM ProductEndOfDay
WHERE CONVERT(Varchar(10), EndOfDayDate, 112)
=
CONVERT(Varchar(10),
DATEADD(dd, 1,
GETDATE()), 112)
)
As B
ON A.ProductId = B.ProductId
Kesimpulan
Setiap feature yang ada di database pasti bermanfaat jika digunakan dengan benar, termasuk cursor. Tidak ada yang salah dengan cursor, hanya kadang kala kita menggunakan cursor bukan buat hal-hal yang disarankan untuk dikerjakan menggunakan cursor.
For any comments, please put in this blog or you can email it directly to me at hendraep@yahoo.com.