Competition
Adam Machanic has a nice competition going on here http://sqlblog.com/blogs/adam_machanic/archive/2009/02/27/t-sql-challenge-grouped-string-concatenation.aspx until the 16th of March 2009.
Please join in! The prize, for the best submission, is a full MSDN subscription, valued at around $10,000. How's that for inspiration!
My first attempt runs for 1.9 seconds and uses 418k reads.
My second attempt runs for 2.1 seconds and uses 334k reads.
Table 'Product'. Scan count 0, logical reads 158866, physical reads 0.
Table 'SalesOrderDetail'. Scan count 31466, logical reads 97140, physical reads 0.
Table 'SalesOrderHeader'. Scan count 38239, logical reads 77321, physical reads 0.
Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0.
Table 'Contact'. Scan count 1, logical reads 569, physical reads 0.
SQL Server Execution Times:
CPU time = 1937 ms, elapsed time = 2107 ms.
Deadline has expired so I now can share my suggestion (second attempt). My first attempt is almost exact the same, but without the derived table sod in the CROSS APPLY q table.
SELECT c.CustomerID,
c.FirstName,
c.LastName,
c.OrderCount,
c.TotalDollarAmount,
c.TotalProductQuantity,
STUFF(p.n, 1, 1, '') AS OrderNumbers,
STUFF(q.n, 1, 1, '') AS ProductNames
FROM (
SELECT soh.CustomerID,
c.FirstName,
c.LastName,
COUNT(soh.SalesOrderNumber) AS OrderCount,
SUM(soh.SubTotal) AS TotalDollarAmount,
SUM(sod.TotalProductQuantity) AS TotalProductQuantity
FROM Person.Contact AS c
INNER JOIN Sales.SalesOrderHeader AS soh ON soh.ContactID = c.ContactID
INNER JOIN (
SELECT SalesOrderID,
SUM(OrderQty) AS TotalProductQuantity
FROM Sales.SalesOrderDetail
GROUP BY SalesOrderID
) AS sod ON sod.SalesOrderID = soh.SalesOrderID
GROUP BY soh.CustomerID,
c.FirstName,
c.LastName
) AS c
CROSS APPLY (
SELECT ',' + soh.SalesOrderNumber
FROM Sales.SalesOrderHeader AS soh
WHERE soh.CustomerID = c.CustomerID
ORDER BY ',' + soh.SalesOrderNumber
FOR XML PATH('')
) AS p(n)
CROSS APPLY (
SELECT ',' + p.Name
FROM (
SELECT sod.ProductID
FROM Sales.SalesOrderHeader AS soh
INNER JOIN Sales.SalesOrderDetail AS sod ON sod.SalesOrderID = soh.SalesOrderID
WHERE soh.CustomerID = c.CustomerID
GROUP BY sod.ProductID
) AS sod
INNER JOIN Production.Product AS p ON p.ProductID = sod.ProductID
ORDER BY ',' + p.Name
FOR XML PATH('')
) AS q(n)
Legacy Comments
MS SQL FREELANCE DBA
2009-02-28 |
re: Competition very interesting... |
Rolf
2009-03-03 |
re: Competition My first attempt takes 2h 56mins to execute when it fails because tempdb has eaten all my disk space :-) |
Peso
2009-03-03 |
re: Competition Keep trying! |
Jacob B
2009-04-01 |
re: Competition Our solutions are very similar! I was happy to get mine to run under 5 seconds so I stopped tunning when I hit something around 3 seconds. If I had spent a few more hours tunning we probably whould have had the exact same execution plan. Any way, you've got me beat by a solid 1.5 seconds and many thousand reads. |
Peso
2009-04-03 |
re: Competition Well, I ran your code on the same computer as the results above and I got 2.6 seconds and 496k reads with Profiler. Statistics are Table 'Product'. Scan count 0, logical reads 242634, physical reads 0. Table 'SalesOrderDetail'. Scan count 31466, logical reads 97140, physical reads 0. Table 'SalesOrderHeader'. Scan count 76478, logical reads 154558, physical reads 0. Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0. Table 'Contact'. Scan count 1, logical reads 569, physical reads 0. |