The case :
We have a table with this data :
Center | Nb of letter |
---|---|
Center 1 | 6504 |
Center 2 | 12874 |
Center 3 | 1944 |
Center 4 | 3418 |
Center 5 | 6050 |
Center 6 | 1938 |
Center 7 | 1893 |
Center 8 | 2489 |
Center 9 | 1810 |
Now, we want to have packages of 100 letters. So for example, for the Center 1, we want 65 packages of 100 letters and one package of 4 letters.
The table with the data is TempData
1. The first solution is to use a cursor :
declare @mod int Set @mod = 100 --The number of letters per package declare @nb int, @start int, @end int, @tot int, @rest int, @cpt int, @centre nvarchar(200) DECLARE @Tbl TABLE ( ID int IDENTITY(1,1) PRIMARY KEY, Centre nvarchar(200), NbStart int, NbEnd int, Total int, Remain int ) declare curseur cursor for select Centre, NbTotal from TempData open curseur fetch next from curseur into @centre, @nb while @@fetch_status = 0 begin SET @tot = @nb SET @start = 1 SET @end = case when @mod < @tot then @mod else @tot end SET @rest = case when @mod < @tot then @tot-@end else 0 end set @cpt = @rest % @mod if @cpt = 0 begin Insert into @Tbl (Centre, NbStart, NbEnd, Total, Remain) select @centre, @start, @end, @tot, @rest end else begin while @cpt > 0 BEGIN Insert into @Tbl (Centre, NbStart, NbEnd, Total, Remain) select @centre, @start, @end, @tot, @rest set @cpt = @rest % @mod SET @start = @end + 1 SET @end = @end + @mod if @end > @tot BEGIN SET @end = @tot SET @rest = 0 END ELSE SET @rest = @tot-@end END end fetch next from curseur into @centre, @nb end close curseur deallocate curseur select * from @Tbl
2. The most simple solution is to use the system table master..spt_values :
declare @mod int Set @mod = 100 --The number of letters per package if OBJECT_ID('tempdb..#temp') is not null drop table #temp SELECT Centre, Nb, NbPage = Nb/@mod + case when Nb % @mod > 0 THEN 1 ELSE 0 END into #temp from TempData SELECT T.Centre, T.Nb, ROW_NUMBER() over (PARTITION BY Centre ORDER BY Centre, NbPage) AS ParcelNumber, NbPerParcel = CASE WHEN ROW_NUMBER() over (PARTITION BY Centre ORDER BY Centre, NbPage) * @mod > Nb THEN Nb % @mod ELSE @mod END FROM #temp t CROSS APPLY ( SELECT * FROM master..spt_values m WHERE m.number <= T.NbPage AND m.number > 0 and m.Type = 'P' ) x if OBJECT_ID('tempdb..#temp') is not null drop table #temp
The source used for this solution was there : http://www.sqlservercentral.com/Forums/Topic1040609-338-1.aspx