在oracle SQL中执行SUM()窗口函数时跳过记录



我有一个场景,有一个容量为1000磅的扶梯。进入自动扶梯的人的总体重不应超过1000磅。line表列有排队的人的姓名、体重和次序。

下面是表语法和其中的值

create table line (id int not null PRIMARY KEY,
name varchar(255) not null,
weight int not null,
turn int unique not null,
check (weight > 0)
);
INSERT INTO LINE VALUES(6,'George Washington', 250, 1);
INSERT INTO LINE VALUES(5,'Thomas Jefferson',175, 7);
INSERT INTO LINE VALUES(3,'John Adams',350, 2);
INSERT INTO LINE VALUES(7,'Thomas Jefferson',800, 3);
INSERT INTO LINE VALUES(1,'James Elephant',500, 6);
INSERT INTO LINE VALUES(2,'Andy',200, 5);
INSERT INTO LINE VALUES(4,'Will Smith',400, 4);

现在我需要写一个查询来打印最后一个进入电梯的人的名字。意思是,最后一个人,电梯的容量将被填满。优先级应该基于TURN值,即第一个人应该被赋予第一优先,第二个人应该被赋予第二优先,以此类推。前两个人的体重之和依次为600,如果下一个人(托马斯·杰斐逊,体重800)进入扶梯,则超过扶梯容量,因此,应忽略/排除此人,并将下一个人(威尔·史密斯,体重400)加入扶梯。现在,所有人的体重之和为1000,此时,输出中应显示威尔·史密斯的名字。

你能指导我写SQL查询吗?

PS:这是我的第一篇文章。如有错误,请忽略。

SQL fiddle link

你正在解决一种类似于背包问题的优化任务,幸运的是,在你的情况下,贪婪遍历就足够了。需要递归查询。在每次迭代中处理一个回合,并确定电梯上的新最后一个人是之前的人还是新的人(请取消注释select *以清楚地理解)。你要找的是CTE最后一个人的名字。(为简单起见,我假设回合是从1开始的连续序列。)

with actual_elevator (name, last_turn, total) as (
select name, turn, weight from line where turn = 1 and weight <= 1000
union all
select case when r.total + l.weight <= 1000 then l.name else r.name end
, l.turn
, case when r.total + l.weight <= 1000 then r.total + l.weight else r.total end
from actual_elevator r
join line l on r.last_turn + 1 = l.turn
where r.total < 1000 -- UPDATE 1
)
--select * from actual_elevator
select name from actual_elevator where last_turn = (select max(turn) from line)

修改小提琴。我不得不称赞你准备了小提琴,指定了db供应商和具体案例的问题描述。并不是每个问[sql]问题的人都那么勤奋。

UPDATE1:当sum恰好为1000时停止迭代,使用where条件在达到限制时停止测试任何新行(修改后的fiddle)。

请注意,当sum小于1000时,迭代必须运行到结束,因为您永远不知道合适的值是在最后一行,直到您看到它。

还要注意算法会贪婪地找到次优解。例如,对于输入800,100,200,它在900处停止,而不会回溯到1000或最大值。这将是完全不同的,更困难的任务,我想你不需要。

最新更新