В SQL Server 2008
это можно сделать с помощью одного оператора MERGE
:
DECLARE @efforts TABLE (id INT NOT NULL PRIMARY KEY, effort INT NOT NULL, name CHAR(1))
INSERT
INTO @efforts
VALUES (1, 1, 'A'),
(2, 1, 'A'),
(3, 8, 'A'),
(4, 10, 'B'),
(5, 4, 'B'),
(6, 1, 'B'),
(7, 10, 'C'),
(8, 3, 'C'),
(9, 30, 'C'),
(10, 60, 'C')
SELECT *
FROM @efforts
ORDER BY
name, id
;WITH total AS
( SELECT *
FROM @efforts e
UNION ALL
SELECT ROW_NUMBER() OVER(ORDER BY name) +
(
SELECT MAX(id)
FROM @efforts
),
40 - SUM(effort),
name
FROM @efforts
GROUP BY
name
HAVING SUM(effort) < 40
),
source AS
(
SELECT *,
(
SELECT SUM(effort)
FROM total ep
WHERE ep.name = e.name
AND ep.id <= e.id
) AS ce,
COALESCE(
(
SELECT SUM(effort)
FROM total ep
WHERE ep.name = e.name
AND ep.id < e.id
), 0) AS cp
FROM total e
)
MERGE
INTO @efforts e
USING source s
ON e.id = s.id
WHEN MATCHED AND 40 BETWEEN cp AND ce THEN
UPDATE
SET e.effort = s.effort + 40 - ce
WHEN MATCHED AND cp > 40 THEN
DELETE
WHEN NOT MATCHED BY TARGET THEN
INSERT (id, effort, name)
VALUES (id, effort, name);
SELECT *
FROM @efforts
ORDER BY
name, id
В SQL Server 2005
вам понадобятся два оператора (в одной транзакции):
DECLARE @efforts TABLE (id INT NOT NULL PRIMARY KEY, effort INT NOT NULL, name CHAR(1))
INSERT
INTO @efforts
VALUES (1, 1, 'A')
INSERT
INTO @efforts
VALUES (2, 1, 'A')
INSERT
INTO @efforts
VALUES (3, 8, 'A')
INSERT
INTO @efforts
VALUES (4, 10, 'B')
INSERT
INTO @efforts
VALUES (5, 4, 'B')
INSERT
INTO @efforts
VALUES (6, 1, 'B')
INSERT
INTO @efforts
VALUES (7, 10, 'C')
INSERT
INTO @efforts
VALUES (8, 3, 'C')
INSERT
INTO @efforts
VALUES (9, 30, 'C')
INSERT
INTO @efforts
VALUES (10, 60, 'C')
;WITH total AS
(
SELECT *,
COALESCE(
(
SELECT SUM(effort)
FROM @efforts ep
WHERE ep.name = e.name
AND ep.id <= e.id
), 0) AS cp
FROM @efforts e
)
DELETE
FROM total
WHERE cp > 40
INSERT
INTO @efforts
SELECT (
SELECT MAX(id)
FROM @efforts
) +
ROW_NUMBER() OVER (ORDER BY name),
40 - SUM(effort),
name
FROM @efforts
GROUP BY
name
HAVING SUM(effort) < 40
SELECT *
FROM @efforts
ORDER BY
name, id