J'ai besoin de regrouper un ensemble de lignes en fonction de l'information suivante Category
et limiter également les lignes combinées en fonction de la colonne SUM(Number)
doit être inférieure ou égale à la colonne @Limit
valeur.
Pour chaque personne distincte Category
J'ai besoin d'identifier les "buckets" qui sont <= @limit
. Si la SOMME( Number
) de toutes les lignes pour un Category
sont <= @Limit
alors il n'y aura qu'un seul seau pour cela Category
(comme 'CCCC' dans l'exemple de données). Cependant, si la méthode SUM( Number
)> @limit
alors il y aura plusieurs rangées de seaux pour cela. Category
(comme 'AAAA' dans les données d'exemple), et chaque godet doit être <= @Limit
. Il peut y avoir autant de seaux que nécessaire. Regardez également Category
dont une ligne est supérieure à la valeur "DDDD". @Limit
tout seul, et est divisé en deux lignes dans le jeu de résultats.
Compte tenu de ces données simplifiées :
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) --EDIT added
INSERT @Detail VALUES (12, 'AAAA',200) --EDIT added
INSERT @Detail VALUES (13, 'AAAA',200) --EDIT added
INSERT @Detail VALUES (14, 'AAAA',200) --EDIT added
SET NOCOUNT OFF
DECLARE @Limit int
SET @Limit=500
J'ai besoin d'un de ces ensembles de résultats :
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 après avoir essayé toutes les réponses
Toutes les tentatives d'une solution basée sur un ensemble ne fonctionnant pas comme il le faudrait, j'opte pour une modification de Réponse de @GalacticJello , modification notée dans le code ci-dessous. En gros, je trouve toutes les lignes où la catégorie entière entre dans le seau et je les INSERTE en utilisant un seul INSERT-SELECT, puis je boucle sur les données restantes en utilisant la boucle sans curseur @GalacticJello. Cela fonctionnera très bien dans ma situation puisqu'il n'y aura pratiquement jamais de lignes traitées par la boucle.
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
SORTIE :
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)