I need to group a rowset based on the Category column, and also limit the merged rows based on the SUM(Number) column to less than or equal to @Limit .
For each individual Category column, I need to identify buckets that are <= @Limit . If the SUM ( Number ) value of all the rows for the Category column is <= @Limit , then there will be only 1 bucket for this Category value (for example, “UDP” in the sample data). However, if SUM ( Number )> @Limit , then for this Category value, several bucket lines will be specified (for example, “AAAA” in the sample data), and each bucket should be <= @Limit . If necessary, there can be so many buckets. Also, look at the Category value "DDDD", its one line is larger than @Limit itself, and is divided into two lines in the result set.
Given these simplified data:
DECLARE @Detail table (DetailID int primary key, Category char(4), Number int) SET NOCOUNT ON INSERT @Detail VALUES ( 1, 'AAAA',100) INSERT @Detail VALUES ( 2, 'AAAA', 50) INSERT @Detail VALUES ( 3, 'AAAA',300) INSERT @Detail VALUES ( 4, 'AAAA',200) INSERT @Detail VALUES ( 5, 'BBBB',500) INSERT @Detail VALUES ( 6, 'CCCC',200) INSERT @Detail VALUES ( 7, 'CCCC',100) INSERT @Detail VALUES ( 8, 'CCCC', 50) INSERT @Detail VALUES ( 9, 'DDDD',800) INSERT @Detail VALUES (10, 'EEEE',100) INSERT @Detail VALUES (11, 'AAAA',200)
I need one of these result sets:
DetailID Bucket | DetailID Category Bucket -------- ------ | -------- -------- ------ 1 1 | 1 'AAAA' 1 2 1 | 2 'AAAA' 1 3 1 | 3 'AAAA' 1 4 2 | 4 'AAAA' 2 11 2 | 11 'AAAA' 2 --EDIT added 12 3 | 12 'AAAA' 3 --EDIT added 13 3 | 13 'AAAA' 3 --EDIT added 14 4 | 14 'AAAA' 4 --EDIT added 5 5 OR 5 'BBBB' 1 6 6 | 6 'CCCC' 1 7 6 | 7 'CCCC' 1 8 6 | 8 'CCCC' 1 9 7 | 9 'DDDD' 1 9 8 | 9 'DDDD' 2 10 9 | 10 'EEEE' 1
EDIT after checking all answers
If all attempts at a dial-based solution do not work as needed, I will proceed with a change to @GalacticJello Answer , the change is noted in the code below. I basically find all the rows in which the entire category fits into the bucket, and insert them using a single INSERT-SELECT, and then iterate over the remaining data using the @GalacticJello cursor. This will work well in my situation, as it is unlikely that there will ever be any lines processed by the loop.
DECLARE @DetailTemp table (PID INT IDENTITY(1,1), DetailID int primary key, Category char(4), Number int) DECLARE @DetailFinal table (DetailID int, Category char(4), Bucket int) ---<<<renamed column to Bucket DECLARE @DetailCount int SET @DetailCount = 0; --------<<<optimization added starts here ;WITH AllSingleBuckets AS ( SELECT Category FROM @Detail GROUP BY Category HAVING SUM(Number)< =@Limit ) INSERT INTO @DetailFinal (DetailID, Category, Bucket) SELECT d.DetailID,d.Category,1 FROM @Detail d INNER JOIN AllSingleBuckets s ON d.Category=s.Category --------<<<optimization added ends here INSERT @DetailTemp --------<<<changed for optimization, added WHERE clause SELECT d.DetailId, d.Category, d.Number FROM @Detail d WHERE NOT EXISTS (SELECT 1 FROM @DetailFinal f WHERE d.Category=f.Category) ORDER BY Category, DetailId SELECT @DetailCount = @@ROWCOUNT DECLARE @CurrentPid int SET @CurrentPid = 1 DECLARE @ThisId int DECLARE @ThisCategory char(4) DECLARE @ThisNumber int DECLARE @CurrentCategory char(4) DECLARE @CurrentSum INT DECLARE @CurrentBucket INT WHILE @CurrentPid <= @DetailCount BEGIN SELECT @ThisId = DetailId, @ThisCategory = Category, @ThisNumber = Number FROM @DetailTemp WHERE PID = @CurrentPid IF @ThisCategory = @CurrentCategory BEGIN IF @CurrentSum + @ThisNumber > @Limit BEGIN SET @CurrentBucket = @CurrentBucket + 1 SET @CurrentSum = @ThisNumber END ELSE BEGIN SET @CurrentSum = @CurrentSum + @ThisNumber END END ELSE BEGIN SET @CurrentBucket = 1 SET @CurrentCategory = @ThisCategory SET @CurrentSum = @ThisNumber END WHILE @CurrentSum > @Limit BEGIN INSERT @DetailFinal SELECT @ThisId, @CurrentCategory, @CurrentBucket SET @CurrentBucket = @CurrentBucket + 1 SET @CurrentSum = @CurrentSum - @Limit END INSERT @DetailFinal SELECT @ThisId, @CurrentCategory, @CurrentBucket SET @CurrentPid = @CurrentPid + 1 END SELECT * from @DetailFinal ORDER BY Category --------<<<added order by
CONCLUSION:
DetailID Category Bucket ----------- -------- ----------- 1 AAAA 1 2 AAAA 1 3 AAAA 1 4 AAAA 2 11 AAAA 2 12 AAAA 3 13 AAAA 3 14 AAAA 4 5 BBBB 1 6 CCCC 1 7 CCCC 1 8 CCCC 1 9 DDDD 1 9 DDDD 2 10 EEEE 1 (15 row(s) affected)