【问题标题】:Skip records while performing SUM() window function in oracle SQL在 oracle SQL 中执行 SUM() 窗口函数时跳过记录
【发布时间】:2021-02-11 07:03:32
【问题描述】:

我有一个场景,有一个容量为 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 值给予优先级,即第一人应给予第一优先权,第二人应给予第二优先权,依此类推。前2人体重之和依次为600,如果下一个人(Thomas Jefferson,Weight-800)进入自动扶梯,则超出自动扶梯容量。因此,应忽略/排除此人并添加下一个人(Will Smith,Weight- 400) 到自动扶梯。现在,所有人体重的总和为 1000,因此,Will Smith 的名字应该显示在输出中。

能否请您指导我为此编写 SQL 查询。

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

SQL fiddle link

【问题讨论】:

  • 您的规则看起来很复杂,您可能想更好地解释它们。
  • 还有指定预期的结果。

标签: sql oracle


【解决方案1】:

您正在解决类似于背包问题的优化任务,除了 - 幸运的是 - 在您的情况下,贪婪遍历就足够了。您需要递归查询。在每次迭代中,都会处理一个回合,并决定电梯上的新最后一个人是前一个还是新的(请取消注释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)

Modified fiddle。 我不得不赞扬你准备小提琴,指定数据库供应商和具体案例的问题描述。不是每个在 SO 上提出 [sql] 问题的人都那么勤奋。

UPDATE1:要在 sum 正好为 1000 时停止迭代,请使用where 条件在达到限制后停止测试任何新行 (modified fiddle)。

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

另请注意,算法贪婪地找到次优解决方案。例如,对于输入 800,100,200,它会在 900 处停止,并且不会回溯到 1000 或最大值。这将是完全不同且更困难的任务,我认为您不需要。

【讨论】:

  • 您好,非常感谢您的快速回复。我正在学习编写复杂的 SQL,再次感谢您在这方面的帮助。
  • @PrathyushaSingavarapu 不清楚它是否真的有帮助。如果是这样,最好接受将问题标记为已解决的答案。
  • @ Tomáš Záluský- 您的查询给出了预期的结果,我对此感到高兴。另一方面,我很想知道有没有其他方法,一旦我们得到总和为 1000 就停止迭代。因为,当前逻辑适用于表中的所有轮次。希望你明白我的意思。
  • @PrathyushaSingavarapu 我没有在您的原始规范中看到它。这是部分可能的。请参阅我的回答中的 UPDATE1。
猜你喜欢
  • 2022-01-19
  • 1970-01-01
  • 2020-10-03
  • 1970-01-01
  • 1970-01-01
  • 2022-01-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多