PDA

View Full Version : Chỉ 1 lệnh thôi


TrungBravo
07-30-2010, 02:44 PM
Yêu cầu: từ dữ liệu thu chi (#TransTemp) và số dư đầu (#BalanceTemp) lập sổ quỹ tiền mặt
#BalanceTemp chỉ bằng 1 câu lệnh tạo ra kết quả có nội dung như sau

+--+---------+----+--------+--------+-------+
|Id| Ngay_Ct | Tk |Tien_Thu|Tien_Chi| So_Du |
+--+---------+----+--------+--------+-------+
| 1| 1/1/2010| 111|__500000|_______0|3500000|
| 2| 1/1/2010| 111|_______0|__400000|3100000|
...
+--+---------+----+--------+--------+-------+

trong đó cột So_Du là số dư của tài khoản sau khi nghiệp vụ phát sinh
Câu lệnh tạo bảng temp như sau

SET NOCOUNT ON;
IF OBJECT_ID('TempDb..#BalanceTemp') IS NOT NULL DROP TABLE #BalanceTemp;
CREATE TABLE #BalanceTemp (Tk Int, Du_Dau_Ky Numeric(18));

INSERT INTO #BalanceTemp (Tk, Du_Dau_Ky) VALUES (111, 3000000);
INSERT INTO #BalanceTemp (Tk, Du_Dau_Ky) VALUES (112, 4000000);

IF OBJECT_ID('TempDb..#TransTemp') IS NOT NULL DROP TABLE #TransTemp

CREATE TABLE #TransTemp (Id Int Identity (1, 1),
Tk Int,
Ngay_Ct datetime,
Tien_Thu Numeric(18),
Tien_Chi Numeric(18))

DECLARE @_i Numeric(8), @_Thu_Chi Int, @_Tien_Thu Numeric(18),
@_Tien_Chi Numeric(18), @_RandomValue Numeric(18), @_Date datetime;
SELECT @_i = 1, @_Thu_Chi = 1, @_Date = 'Jan 1, 2010';

WHILE @_i <= 10000
BEGIN
SET @_RandomValue = (RAND() * 1000 + RAND() * 1000 + RAND() * 1000) + (RAND() * 100 + RAND() * 100 + RAND() * 100);
IF @_Thu_Chi = 1
SELECT @_Tien_Thu = @_RandomValue , @_Tien_Chi = 0, @_Thu_Chi = 0;
ELSE
SELECT @_Tien_Thu = 0, @_Tien_Chi = @_RandomValue, @_Thu_Chi = 1;

INSERT INTO #TransTemp (Ngay_Ct, Tk, Tien_Thu, Tien_Chi)
VALUES (DATEADD(day, RAND(), @_Date), 111, @_Tien_Thu, @_Tien_Chi);

IF @_Thu_Chi = 1
SET @_Date = DATEADD(day, 1, @_Date)

SET @_i = @_i + 1;
END

CREATE UNIQUE INDEX #PK_TranTemp_Id ON #TransTemp (Id)

chautinhtri
08-05-2010, 09:17 AM
SELECT t.id, t.Ngay_Ct, t.Tien_Thu, t.Tien_Chi, rt.Tien_Thu - rt.Tien_Chi AS Du_Cuoi
FROM #TransTemp t
cross apply (SELECT SUM(Tien_Thu) AS Tien_Thu, SUM(Tien_Chi) AS Tien_Chi FROM #TransTemp WHERE id <= t.id) AS rt
ORDER BY t.id

Trả biết chạy thế nào mong anh em đóng góp thêm
:D

TrungBravo
08-05-2010, 11:02 AM
Cán ơn bác chautinhtri đă có phương án cho em. Đây là phương án chạy nhanh và sáng sủa hơn cái em đang có (nhưng chỉ nhanh hơn có 2 giây)
Nhưng thiếu chưa xử lư cái #BalanceTemp, dẫu sao cũng tuyệt vời :)
Phát huy tinh thần của bác chautinhtri, em vẫn mong nhận được các phương án nữa

chautinhtri
08-05-2010, 01:34 PM
Nếu số ḍng của bác <= 32767 ḍng th́ có lệnh c̣n nhanh hơn
Nhưng chắc khó có trường hợp đấy
:D

TrungBravo
08-05-2010, 04:58 PM
Phương án ban đầu chạy mất 15 giây

WITH RunningBalance (Id, So_Du)
AS
(
SELECT A.Id, (B.Tien_Thu - B.Tien_Chi) AS So_Du
FROM #TransTemp A CROSS JOIN
#TransTemp B
WHERE B.ID <= A.ID
)
SELECT #TransTemp.Id, Ngay_Ct, Tien_Thu, Tien_Chi, So_Du + #BalanceTemp.Du_Dau_Ky AS [So Du]
FROM #TransTemp LEFT OUTER JOIN
(SELECT Id, SUM(So_Du) So_Du
FROM RunningBalance T GROUP BY Id) Bal
ON #TransTemp.Id = Bal.Id
LEFT OUTER JOIN #BalanceTemp ON #TransTemp.Tk = #BalanceTemp.Tk
ORDER BY #TransTemp.Id

Phương án hiện tại chạy mất 9 giây

SELECT A.Id, Ngay_Ct, A.Tien_Thu, A.Tien_Chi,
(SELECT SUM(Tien_Thu - Tien_Chi) FROM #TransTemp WHERE Id <= A.Id) + C.Du_Dau_Ky AS [So Du]
FROM #TransTemp A
LEFT OUTER JOIN #BalanceTemp C ON A.Tk = C.Tk
ORDER BY A.Id

Cần phương án chạy tối đa là 2 hoặc 3 giây