删除一些行以使每个组的总数低于阈值
Delete some rows to bring each group total below the threshold
我有一个 Ledger
table:
CREATE TABLE Ledger
(
PersonID int,
Narration varchar(255),
Payment int(255)
);
INSERT INTO Ledger(PersonID, Narration, Payment)
VALUES (1, 'Snacks 1', 5);
INSERT INTO Ledger(PersonID, Narration, Payment)
VALUES (1, 'Snacks 2', 10);
INSERT INTO Ledger(PersonID, Narration, Payment)
VALUES (2, 'Snacks 3', 7);
INSERT INTO Ledger(PersonID, Narration, Payment)
VALUES (1, 'Snacks 4', 6);
INSERT INTO Ledger(PersonID, Narration, Payment)
VALUES (2, 'Snacks 5', 3);
INSERT INTO Ledger(PersonID, Narration, Payment)
VALUES (1, 'Snacks 6', 1);
table 看起来像这样:
PersonID Narration Payment
_____________________________________________
1 Snacks 1 5
1 Snacks 2 10
2 Snacks 3 7
1 Snacks 4 6
2 Snacks 5 3
1 Snacks 6 1
这里PersonID=1
一共花了22,PersonID=2
一共花了10。
我的要求是将总数 Payment
减少到小于或等于 20。没有唯一的列。 我希望删除记录以使总数 Payment
低于或等于 20。
在上面table中,PersonID=1
一共Payment
大于20,所以我需要删除一些记录来减少总支付。
我的预期输出
PersonID Narration Payment
_____________________________________________
1 Snacks 2 10
2 Snacks 3 7
1 Snacks 4 6
2 Snacks 5 3
1 Snacks 6 1
这里我去掉了
1 Snacks 1 5
现在PersonID=1
的总Payment
是17,低于20
根据逻辑我们必须删除记录。
请在 SQL 服务器和 MySQL 方面协助我。我的第一选择是 SQL 服务器。
这是 SQL Server 2012+ 的一种可能变体。
示例数据
CREATE TABLE Ledger
(
PersonID int,
Narration varchar(255),
Payment int
);
INSERT INTO Ledger(PersonID, Narration, Payment) VALUES
(1, 'Snacks 1', 5),
(1, 'Snacks 2', 10),
(2, 'Snacks 3', 7),
(1, 'Snacks 4', 6),
(2, 'Snacks 5', 3),
(1, 'Snacks 6', 1);
SELECT *
FROM Ledger
ORDER BY PersonID, Payment;
+----------+-----------+---------+
| PersonID | Narration | Payment |
+----------+-----------+---------+
| 1 | Snacks 6 | 1 |
| 1 | Snacks 1 | 5 |
| 1 | Snacks 4 | 6 |
| 1 | Snacks 2 | 10 |
| 2 | Snacks 5 | 3 |
| 2 | Snacks 3 | 7 |
+----------+-----------+---------+
查询
我们可以计算 运行 总数以确定我们要保留哪些行以及要删除哪些行。您可以通过选择 运行 总数中的排序来调整行选择的逻辑。在此示例中,我将从最小的 Payment
开始计算 运行 总数,因此将保留最小 Payment
的行。
此查询显示计算,以了解其工作原理:
WITH
CTE
AS
(
SELECT
PersonID
,Narration
,Payment
,SUM(Payment) OVER
(PARTITION BY PersonID ORDER BY Payment
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS ss
FROM Ledger
)
SELECT *
FROM CTE
ORDER BY PersonID, Payment;
+----------+-----------+---------+----+
| PersonID | Narration | Payment | ss |
+----------+-----------+---------+----+
| 1 | Snacks 6 | 1 | 1 |
| 1 | Snacks 1 | 5 | 6 |
| 1 | Snacks 4 | 6 | 12 |
| 1 | Snacks 2 | 10 | 22 |
| 2 | Snacks 5 | 3 | 3 |
| 2 | Snacks 3 | 7 | 10 |
+----------+-----------+---------+----+
这个查询实际上删除了行:
WITH
CTE
AS
(
SELECT
PersonID
,Narration
,Payment
,SUM(Payment) OVER
(PARTITION BY PersonID ORDER BY Payment
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS ss
FROM Ledger
)
DELETE FROM CTE
WHERE ss > 20;
结果
SELECT *
FROM Ledger
ORDER BY PersonID, Payment;
+----------+-----------+---------+
| PersonID | Narration | Payment |
+----------+-----------+---------+
| 1 | Snacks 6 | 1 |
| 1 | Snacks 1 | 5 |
| 1 | Snacks 4 | 6 |
| 2 | Snacks 5 | 3 |
| 2 | Snacks 3 | 7 |
+----------+-----------+---------+
您还可以通过以下查询获得所需的输出:-
DECLARE @PID int ,@PID1 int,@Narr VARCHAR(250),@Payment decimal(18,2),@Payment1 decimal(18,2),@cnt int
SET @cnt = 20
set @Payment1=0
set @PID1=0
Create table #t1(PersonID int,Narration varchar(250),Payment decimal(18,2));
DECLARE db_cursor CURSOR FOR
SELECT PersonID,Narration,Payment from Ledger order by personid ,Payment
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO @PID,@Narr,@Payment
WHILE @@FETCH_STATUS = 0
BEGIN
if (@PID1 <> @PID)
BEGIN
SET @Payment1 = 0
END
set @PID1 = @PID
SET @Payment1 = @Payment1 + @Payment
If(@Payment1 <= 20)
begin
Insert into #t1(PersonID,Narration,Payment)
values(@PID,@Narr,@Payment)
end
FETCH NEXT FROM db_cursor INTO @PID,@Narr,@Payment
end
CLOSE db_cursor
DEALLOCATE db_cursor
select * from #t1
order by personid
drop table #t1
同样进行了测试,得到了以下输入的以下输出:-
输入:-
1 Snacks 1 5
1 Snacks 2 10
1 Snacks 4 6
1 Snacks 6 1
2 Snacks 5 3
2 Snacks 3 7
3 Snacks 7 15
3 Snacks 8 15
4 Snacks 9 10
输出:-
1 Snacks 6 1.00
1 Snacks 1 5.00
1 Snacks 4 6.00
2 Snacks 5 3.00
2 Snacks 3 7.00
3 Snacks 7 15.00
4 Snacks 9 10.00
我有一个 Ledger
table:
CREATE TABLE Ledger
(
PersonID int,
Narration varchar(255),
Payment int(255)
);
INSERT INTO Ledger(PersonID, Narration, Payment)
VALUES (1, 'Snacks 1', 5);
INSERT INTO Ledger(PersonID, Narration, Payment)
VALUES (1, 'Snacks 2', 10);
INSERT INTO Ledger(PersonID, Narration, Payment)
VALUES (2, 'Snacks 3', 7);
INSERT INTO Ledger(PersonID, Narration, Payment)
VALUES (1, 'Snacks 4', 6);
INSERT INTO Ledger(PersonID, Narration, Payment)
VALUES (2, 'Snacks 5', 3);
INSERT INTO Ledger(PersonID, Narration, Payment)
VALUES (1, 'Snacks 6', 1);
table 看起来像这样:
PersonID Narration Payment
_____________________________________________
1 Snacks 1 5
1 Snacks 2 10
2 Snacks 3 7
1 Snacks 4 6
2 Snacks 5 3
1 Snacks 6 1
这里PersonID=1
一共花了22,PersonID=2
一共花了10。
我的要求是将总数 Payment
减少到小于或等于 20。没有唯一的列。 我希望删除记录以使总数 Payment
低于或等于 20。
在上面table中,PersonID=1
一共Payment
大于20,所以我需要删除一些记录来减少总支付。
我的预期输出
PersonID Narration Payment
_____________________________________________
1 Snacks 2 10
2 Snacks 3 7
1 Snacks 4 6
2 Snacks 5 3
1 Snacks 6 1
这里我去掉了
1 Snacks 1 5
现在PersonID=1
的总Payment
是17,低于20
根据逻辑我们必须删除记录。
请在 SQL 服务器和 MySQL 方面协助我。我的第一选择是 SQL 服务器。
这是 SQL Server 2012+ 的一种可能变体。
示例数据
CREATE TABLE Ledger
(
PersonID int,
Narration varchar(255),
Payment int
);
INSERT INTO Ledger(PersonID, Narration, Payment) VALUES
(1, 'Snacks 1', 5),
(1, 'Snacks 2', 10),
(2, 'Snacks 3', 7),
(1, 'Snacks 4', 6),
(2, 'Snacks 5', 3),
(1, 'Snacks 6', 1);
SELECT *
FROM Ledger
ORDER BY PersonID, Payment;
+----------+-----------+---------+
| PersonID | Narration | Payment |
+----------+-----------+---------+
| 1 | Snacks 6 | 1 |
| 1 | Snacks 1 | 5 |
| 1 | Snacks 4 | 6 |
| 1 | Snacks 2 | 10 |
| 2 | Snacks 5 | 3 |
| 2 | Snacks 3 | 7 |
+----------+-----------+---------+
查询
我们可以计算 运行 总数以确定我们要保留哪些行以及要删除哪些行。您可以通过选择 运行 总数中的排序来调整行选择的逻辑。在此示例中,我将从最小的 Payment
开始计算 运行 总数,因此将保留最小 Payment
的行。
此查询显示计算,以了解其工作原理:
WITH
CTE
AS
(
SELECT
PersonID
,Narration
,Payment
,SUM(Payment) OVER
(PARTITION BY PersonID ORDER BY Payment
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS ss
FROM Ledger
)
SELECT *
FROM CTE
ORDER BY PersonID, Payment;
+----------+-----------+---------+----+
| PersonID | Narration | Payment | ss |
+----------+-----------+---------+----+
| 1 | Snacks 6 | 1 | 1 |
| 1 | Snacks 1 | 5 | 6 |
| 1 | Snacks 4 | 6 | 12 |
| 1 | Snacks 2 | 10 | 22 |
| 2 | Snacks 5 | 3 | 3 |
| 2 | Snacks 3 | 7 | 10 |
+----------+-----------+---------+----+
这个查询实际上删除了行:
WITH
CTE
AS
(
SELECT
PersonID
,Narration
,Payment
,SUM(Payment) OVER
(PARTITION BY PersonID ORDER BY Payment
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS ss
FROM Ledger
)
DELETE FROM CTE
WHERE ss > 20;
结果
SELECT *
FROM Ledger
ORDER BY PersonID, Payment;
+----------+-----------+---------+
| PersonID | Narration | Payment |
+----------+-----------+---------+
| 1 | Snacks 6 | 1 |
| 1 | Snacks 1 | 5 |
| 1 | Snacks 4 | 6 |
| 2 | Snacks 5 | 3 |
| 2 | Snacks 3 | 7 |
+----------+-----------+---------+
您还可以通过以下查询获得所需的输出:-
DECLARE @PID int ,@PID1 int,@Narr VARCHAR(250),@Payment decimal(18,2),@Payment1 decimal(18,2),@cnt int
SET @cnt = 20
set @Payment1=0
set @PID1=0
Create table #t1(PersonID int,Narration varchar(250),Payment decimal(18,2));
DECLARE db_cursor CURSOR FOR
SELECT PersonID,Narration,Payment from Ledger order by personid ,Payment
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO @PID,@Narr,@Payment
WHILE @@FETCH_STATUS = 0
BEGIN
if (@PID1 <> @PID)
BEGIN
SET @Payment1 = 0
END
set @PID1 = @PID
SET @Payment1 = @Payment1 + @Payment
If(@Payment1 <= 20)
begin
Insert into #t1(PersonID,Narration,Payment)
values(@PID,@Narr,@Payment)
end
FETCH NEXT FROM db_cursor INTO @PID,@Narr,@Payment
end
CLOSE db_cursor
DEALLOCATE db_cursor
select * from #t1
order by personid
drop table #t1
同样进行了测试,得到了以下输入的以下输出:-
输入:-
1 Snacks 1 5
1 Snacks 2 10
1 Snacks 4 6
1 Snacks 6 1
2 Snacks 5 3
2 Snacks 3 7
3 Snacks 7 15
3 Snacks 8 15
4 Snacks 9 10
输出:-
1 Snacks 6 1.00
1 Snacks 1 5.00
1 Snacks 4 6.00
2 Snacks 5 3.00
2 Snacks 3 7.00
3 Snacks 7 15.00
4 Snacks 9 10.00