Refactoring SQL
Okay, I just went through a SQL refactoring tha I consider interesting. We'll start with this code:
Cursor transactions IS
SELECT L.CustomerId ,
Sum(Y.Debt) Sum_Debt ,
Sum(Y.Credit) Sum_Credit
FROM Transactions Y join
Customers L
ON L.CustomerId = Y.CustomerId
AND L.Status NOT IN (1 , 2 , 3)
GROUP BY L.CustomerId
For rec0 IN transactions
UPDATE CustomerStatus
SET Debt = rec0.Sum_Debt,
Credit = rec0.Sum_Credit
WHERE CustomerId = rec0.CustomerId
End
The above is using Oracle syntax, which I find much saner for cursors than what SQL Server requires you to do. This is undoubtly one of the reasons that cursors are so much more popular in Oracle than in SQL Server.
From now on I'm using SQL Server syntax, btw. The first thing that I did was to remove the cursor. I did it by simply adding a FROM clasue to the update, like this:
UPDATE CustomerStatus
SET Debt = rec0.Sum_Debt,
Credit = rec0.Sum_Credit
FROM
(
SELECT L.CustomerId ,
Sum(Y.Debt) Sum_Debt ,
Sum(Y.Credit) Sum_Credit
FROM Transactions Y join
Customers L
ON L.CustomerId = Y.CustomerId
AND L.Status NOT IN (1 , 2 , 3)
GROUP BY L.CustomerId
) rec0
WHERE CustomerId = rec0.CustomerId
WITH rec0 (CustomerId, Sum_Debt, Sum_Credit) AS
(
SELECT L.CustomerId ,
Sum(Y.Debt) Sum_Debt ,
Sum(Y.Credit) Sum_Credit
FROM Transactions Y join
Customers L
ON L.CustomerId = Y.CustomerId
AND L.Status NOT IN (1 , 2 , 3)
GROUP BY L.CustomerId
)
UPDATE CustomerStatus
SET Debt = rec0.Sum_Debt,
Credit = rec0.Sum_Credit
FROM rec0
WHERE CustomerId = rec0.CustomerId
I find this much easier to understand than the previous one, and it's performance it just fine. One thing I wish I could do is either nest WITH statements or cascade them.
By nesting I mean something like:
WITH DrunkCustomers (CustomerId) AS
(
WITH Bar(CustomerId)
AS
{
SELECT CustomerId FROM Transactions
WHERE Payee like '%bar%'
}
SELECT L.CustomerId ,
Sum(Y.Debt) Sum_Debt ,
Sum(Y.Credit) Sum_Credit
FROM Bar Y join
Customers L
ON L.CustomerId = Y.CustomerId
AND L.Status NOT IN (1 , 2 , 3)
GROUP BY L.CustomerId
)
By cascading I mean:
WITH Bar(CustomerId)
AS
{
SELECT CustomerId FROM Transactions
WHERE Payee like '%bar%'
}
WITH DrunkCustomers (CustomerId) AS
(
SELECT L.CustomerId ,
Sum(Y.Debt) Sum_Debt ,
Sum(Y.Credit) Sum_Credit
FROM Bar Y join
Customers L
ON L.CustomerId = Y.CustomerId
AND L.Status NOT IN (1 , 2 , 3)
GROUP BY L.CustomerId
)
Sadly, none of those options works.
Comments
Comment preview