| Author |
Topic |
|
Transact Charlie
Master Smack Fu Yak Hacker
3451 Posts |
Posted - 2009-05-19 : 04:47:18
|
Hello all.Say I have the following table wnad data DECLARE @costBreakdown TABLE ( [employeeID] INT , [startDate] DATETIME , [endDate] DATETIME , [productID] INT , [optionID] INT , [cost] MONEY )INSERT @costBreakdown ( [employeeID] , [startDate] , [endDate] , [productID] , [optionID] , [cost] ) SELECT 1, '20080101', '20080120', 1, 1, 100UNION SELECT 1, '20080121', '20080331', 1, 1, 100UNION SELECT 1, '20080401', '20081231', 1, 2, 200UNION SELECT 1, '20090101', '20090331', 1, 1, 100UNION SELECT 2, '20080101', '20080412', 2, 5, 1000UNION SELECT 2, '20080414', '20081231', 2, 5, 1000SELECT *FROM @costBreakdownORDER BY [employeeID] , [productId] , [startDate] , [endDate] I need to combine the concurrent dates for the same product / option as long as there is no break between the [enddate] and [startdate] of the following entry.So for that dataset I need to combine the first two rows for ([employeeId] = 1) into 1 row with the start Date of 20080101 and the end Date of 20080331.Because there is a change of option for the next time chunk I don't want to combine it with the other [product] = 1, [option] = 1 entry.For employee = 2 I don't want to combine the rows because the entries are not concurrent -- there is 1 day gap inbetween.The cost is an annual value so does not need changed. Also products with the same options cannot have different costs so I don't have to worry about that.My required result set is:employeeID startDate endDate productID optionID cost----------- ----------------------- ----------------------- ----------- ----------- ---------------------1 2008-01-01 00:00:00.000 2008-03-31 00:00:00.000 1 1 100.001 2008-04-01 00:00:00.000 2008-12-31 00:00:00.000 1 2 200.001 2009-01-01 00:00:00.000 2009-03-31 00:00:00.000 1 1 100.002 2008-01-01 00:00:00.000 2008-04-12 00:00:00.000 2 5 1000.002 2008-04-14 00:00:00.000 2008-12-31 00:00:00.000 2 5 1000.00 Cheers.Charlie===============================================================Msg 3903, Level 16, State 1, Line 1736The ROLLBACK TRANSACTION request has no corresponding BEGIN TRANSACTION |
|
|
SwePeso
Patron Saint of Lost Yaks
30421 Posts |
Posted - 2009-05-19 : 05:14:11
|
A cte will do. :-) E 12°55'05.63"N 56°04'39.26" |
 |
|
|
Transact Charlie
Master Smack Fu Yak Hacker
3451 Posts |
Posted - 2009-05-19 : 05:18:57
|
Cheers Peso! I had thought of that but am being a little slow this morning coming up with all the details (currently bogged down in some ROW_NUMBER() ideas)I've got this:SELECT *FROM ( SELECT ROW_NUMBER() OVER(ORDER BY [employeeID], [productId], [startDate], [endDate]) AS [row] , * FROM @costBreakdown ) a JOIN ( SELECT ROW_NUMBER() OVER(ORDER BY [employeeID], [productId], [startDate], [endDate]) AS [row] , * FROM @costBreakdown ) b ON b.[row] = a.[row] + 1 AND DATEDIFF(DAY, a.[endDate], b.[startDate]) = 1 AND a.[productId] = b.[productID] AND a.[optionID] = b.[optionID] to identify target rows.As my real dataset can be huge I'm thinking best to copy all the rows that don't fit that criteria and then run a CTE on the ones that do?Charlie===============================================================Msg 3903, Level 16, State 1, Line 1736The ROLLBACK TRANSACTION request has no corresponding BEGIN TRANSACTION |
 |
|
|
Transact Charlie
Master Smack Fu Yak Hacker
3451 Posts |
Posted - 2009-05-19 : 05:20:07
|
| Maybe I just need some coffee. :)Charlie===============================================================Msg 3903, Level 16, State 1, Line 1736The ROLLBACK TRANSACTION request has no corresponding BEGIN TRANSACTION |
 |
|
|
SwePeso
Patron Saint of Lost Yaks
30421 Posts |
Posted - 2009-05-19 : 05:32:37
|
CTE anchor part:Select earliest entry for all employees with columns employeeid, startdate, enddate, total start date and total end dateCTE recursive part:Get next entry (from another cte with row_number() thingy).If dates "match", change total end date. If no "match" change total start date and total end date. E 12°55'05.63"N 56°04'39.26" |
 |
|
|
Transact Charlie
Master Smack Fu Yak Hacker
3451 Posts |
Posted - 2009-05-19 : 05:49:47
|
| Cheers again Peso -- I'm going to go away and get something that works. I'll post it when I do for the inevitable "improvements":)Charlie===============================================================Msg 3903, Level 16, State 1, Line 1736The ROLLBACK TRANSACTION request has no corresponding BEGIN TRANSACTION |
 |
|
|
Transact Charlie
Master Smack Fu Yak Hacker
3451 Posts |
Posted - 2009-05-19 : 06:36:13
|
Ok -- I have a solution!I've changed the data slightly (just putting some more in it and adding a required primary key)Here it is - I'm sure it can be improved!DECLARE @costBreakdown TABLE ( [ID] INT IDENTITY(1,1) PRIMARY KEY , [employeeID] INT , [startDate] DATETIME , [endDate] DATETIME , [productID] INT , [optionID] INT , [cost] MONEY )INSERT @costBreakdown ( [employeeID] , [startDate] , [endDate] , [productID] , [optionID] , [cost] ) SELECT 1, '20080101', '20080120', 1, 1, 100UNION SELECT 1, '20080121', '20080331', 1, 1, 100UNION SELECT 1, '20080401', '20080630', 1, 1, 100UNION SELECT 1, '20080701', '20081231', 1, 2, 200UNION SELECT 1, '20090101', '20090331', 1, 1, 100UNION SELECT 1, '20090401', '20091231', 1, 1, 100UNION SELECT 2, '20080101', '20080412', 2, 5, 1000UNION SELECT 2, '20080414', '20081231', 2, 5, 1000SELECT [employeeID] , [productId] , [optionID] , [StartDate] , [EndDate] , [cost]FROM @costBreakdown-- CTE to combine concurrent dates; WITH orders AS ( SELECT ROW_NUMBER() OVER(ORDER BY [employeeID], [productId], [startDate], [endDate]) AS [row] , [Id] , [employeeId] , [productId] , [optionId] , [startDate] , [endDate] FROM @costBreakdown ), recur AS ( -- Parent Decleration SELECT [ID] , [employeeID] , [productID] , [optionID] , [startDate] , [endDate] , [startDate] AS [baseStartDate] , [endDate] AS [baseEndDate] , 0 AS [level] FROM @costBreakdown WHERE [Id] NOT IN ( SELECT b.[ID] FROM orders a JOIN orders b ON b.[row] = a.[row] + 1 AND b.[startDate] = a.[endDate] + 1 AND b.[optionId] = a.[optionId] AND b.[productId] = a.[productId] ) -- Recursive Decleration UNION ALL SELECT r.[ID] , r.[employeeId] , r.[productId] , r.[optionId] , o.[startDate] , o.[endDate] , c.[startDate] , o.[endDate] , r.[level] + 1 FROM orders o JOIN recur r ON r.[employeeId] = o.[employeeID] AND r.[productId] = o.[productId] AND r.[optionId] = o.[optionID] AND DATEDIFF(DAY, r.[endDate], o.[startDate]) = 1 JOIN @costBreakdown c ON c.[Id] = r.[Id] )SELECT c.[employeeID] , c.[productId] , c.[optionID] , r.[baseStartDate] , r.[baseEndDate] , c.[cost]FROM ( SELECT ROW_NUMBER() OVER(PARTITION BY [Id] ORDER BY [level] DESC) AS [rowPos] , [ID] , [baseStartDate] , [baseEndDate] FROM recur ) r JOIN @costBreakdown c ON c.[Id] = r.[Id]WHERE r.[rowPos] = 1 Charlie===============================================================Msg 3903, Level 16, State 1, Line 1736The ROLLBACK TRANSACTION request has no corresponding BEGIN TRANSACTION |
 |
|
|
Lamprey
Master Smack Fu Yak Hacker
4614 Posts |
Posted - 2009-05-19 : 12:32:26
|
Here is a simple way, but I'm not 100% about the Partitioning for your real data (but it does work for the sample data):SELECT employeeID, startDate, EndDate, productID, optionID, costFROM( SELECT A.employeeID, A.startDate, COALESCE(B.EndDate, A.EndDate) AS EndDate, A.productID, A.optionID, A.cost, ROW_NUMBER() OVER (PARTITION BY A.employeeID, COALESCE(B.EndDate, A.EndDate), A.productID, A.optionID, A.cost ORDER BY A.employeeID, COALESCE(B.EndDate, A.EndDate), A.productID, A.optionID, A.cost ) AS RowNum FROM @costBreakdown AS A LEFT OUTER JOIN @costBreakdown AS B ON A.employeeID = B.employeeID AND A.productID = B.productID AND A.optionID = B.optionID AND A.endDate = B.startDate - 1) AS TWHERE RowNum = 1 |
 |
|
|
Transact Charlie
Master Smack Fu Yak Hacker
3451 Posts |
Posted - 2009-05-20 : 04:54:42
|
Thanks for the input Lamps!Your script doesn't work for the following set of data:DECLARE @costBreakdown TABLE ( [ID] INT IDENTITY(1,1) PRIMARY KEY , [employeeID] INT , [startDate] DATETIME , [endDate] DATETIME , [productID] INT , [optionID] INT , [cost] MONEY )INSERT @costBreakdown ( [employeeID] , [startDate] , [endDate] , [productID] , [optionID] , [cost] ) SELECT 1, '20080101', '20080120', 1, 1, 100UNION SELECT 1, '20080121', '20080331', 1, 1, 100UNION SELECT 1, '20080401', '20080630', 1, 1, 100UNION SELECT 1, '20080701', '20081231', 1, 2, 200UNION SELECT 1, '20090101', '20090331', 1, 1, 100UNION SELECT 1, '20090401', '20091231', 1, 1, 100UNION SELECT 2, '20080101', '20080412', 2, 5, 1000UNION SELECT 2, '20080414', '20081231', 2, 5, 1000 Your code outputs:employeeID startDate EndDate productID optionID cost----------- ----------------------- ----------------------- ----------- ----------- ---------------------1 2008-01-01 00:00:00.000 2008-03-31 00:00:00.000 1 1 100.001 2008-01-21 00:00:00.000 2008-06-30 00:00:00.000 1 1 100.001 2008-07-01 00:00:00.000 2008-12-31 00:00:00.000 1 2 200.001 2009-01-01 00:00:00.000 2009-12-31 00:00:00.000 1 1 100.002 2008-01-01 00:00:00.000 2008-04-12 00:00:00.000 2 5 1000.002 2008-04-14 00:00:00.000 2008-12-31 00:00:00.000 2 5 1000.00 Which is a little mangled.-- The end result should amalgamate the first 3 rows (of the initial data set) into 1 row. Your script doesn't do that. I need a way to combine practically any number of sequential rows into 1 (though I'd be very surprised if my real data has any more than 10 concurrent rows for any particular employee / product pairing).I appreciate that it does work for the initial sample set I posted so my bad for posting incomplete data!Looks faster than my recursive cte though....Charlie===============================================================Msg 3903, Level 16, State 1, Line 1736The ROLLBACK TRANSACTION request has no corresponding BEGIN TRANSACTION |
 |
|
|
Lamprey
Master Smack Fu Yak Hacker
4614 Posts |
Posted - 2009-05-20 : 12:15:36
|
| Ahh well.. it was worth a shot... :) |
 |
|
|
|
|
|