【问题标题】:Loop or Recursion in SQL or use Python?SQL中的循环或递归或使用Python?
【发布时间】:2021-06-17 00:00:24
【问题描述】:

假设我有下表:

A B C D
10 14 15 16
9 13 14 14
8 12 13 12
7 9 12 10
6 8 11 8
5 8 10 6

这里的 A-B-C-D 是购物车。我想购买购物车中的商品。商品的价格在每一行中。例如,购物车 A 有 6 件商品,价格为 (10, 9, 8, 7, 6, 5)。

如果另一个购物车中没有更便宜的商品,我只想购买给定购物车中的商品,否则我想从另一个购物车购买商品。当我购买每件商品时,我会将其标记为已购买。每个购物车也有不同的购买能力。 A最多可以买5个,B最多6个,C最多4个,D最多1个。

购物车 A 是锚点,所以如果 A 达到容量,我们就会停下来。

原来如此。

购买:

  1. 5 来自 A
  2. 6 来自 A
  3. 6 来自 D - D 在此次购买后达到产能
  4. 7 来自 A
  5. 8 来自 A
  6. 8 来自 B
  7. 8 来自 B
  8. 9 从 A - A 达到容量

由于 A 达到了它的容量,它会在这里结束。

您将如何在 SQL 中执行此操作。我想我可以使用循环,但我读过 SQL 是为了提高效率而基于集合的。我正在尝试做的似乎需要循环或递归。这是正确的方法吗,我应该为此使用 Python 吗?

感谢您的帮助!

【问题讨论】:

  • 用您正在使用的数据库标记您的问题。
  • 更新了标签,使用 mysql。谢谢!
  • 请说明流程结束的原因和时间?你写了“既然 A 达到了它的容量,它会在这里结束。”,但 A 在那之前两步就达到了它的容量。
  • 很抱歉,该过程应该在第 8 步结束。我将编辑我的问题。
  • @RareWiz 好的,看看我的回答

标签: python mysql sql loops recursion


【解决方案1】:

如果我理解正确,您可以通过反透视、枚举行和过滤来轻松完成此操作:

select t.*
from (select cart, val,
             row_number() over partition by cart order by val) as seqnum
      from ((select 'A' as cart, A as val from t) union all
            (select 'B' as cart, B from t) union all
            (select 'C' as cart, C from t) union all
            (select 'D' as cart, D from t)
           ) t
     ) t
where (cart = 'A' and seqnum <= 5) or
      (cart = 'A' and seqnum <= 6) or
      (cart = 'A' and seqnum <= 4) or
      (cart = 'A' and seqnum <= 1)
order by val, cart;

注意:根据您使用的数据库,可能有更简单的方法可以取消数据透视。

【讨论】:

  • 谢谢。需要明确的是,我真正想要的是一种比较每个购物车中的最低价格并购买更便宜的商品的方法。然后再次执行该过程,直到购物车 A 达到容量。我相信这个特定的脚本只是从每个购物车中返回最便宜的物品,但没有进行任何比较来决定购买什么。
  • @RareWiz 。 . .我认为这是相同的过程。这会按价格“按顺序”选择商品,这就是您的问题所显示的内容。
  • 明白了,有道理。我做了一些调整。我更改了 where 子句以查看所有购物车,而不仅仅是购物车 A,我认为这可能是一个错字。它返回 16 行 (5+6+4+1)。我如何将其限制为仅 8 行,因为此时购物车 A 已达到其容量?感谢您的帮助!
  • mysql什么时候得到partition的特性?
  • @谢谢。 . . MySQL 8.0 于 2018 年 4 月发布。
【解决方案2】:

这应该可行:

with tab as (
select 'A' as cart, A as value from table
union
select 'B', B from table
union
select 'C', C from table
union
select 'D', D from table
)
select * from (
    select tab.*, 
    case 
        when 
            sum(case when cart = 'A' then 1 else 0 end) over(order by value) < 5
            or sum(case when cart = 'A' then 1 else 0 end) over(order by value) = 5 and cart = 'A'
        then 1 
        else 0 
    end as selected
    from tab
) items
where items.selected = 1

【讨论】:

    【解决方案3】:

    如果您正在寻找 Python 解决方案,可以使用 while 循环:

    from collections import deque
    full_data = [{'a': 10, 'b': 14, 'c': 15, 'd': 16}, {'a': 9, 'b': 13, 'c': 14, 'd': 14}, {'a': 8, 'b': 12, 'c': 13, 'd': 12}, {'a': 7, 'b': 9, 'c': 12, 'd': 10}, {'a': 6, 'b': 8, 'c': 11, 'd': 8}, {'a': 5, 'b': 8, 'c': 10, 'd': 6}]
    data = {i:deque(sorted([j[i] for j in full_data])) for i in ['a', 'b', 'c', 'd']}
    s, m = [], {'a':5, 'b':6, 'c':4, 'd':1}
    while m['a']:
       a, _, _ = min([(a, b[0], i) for i, [a, b] in enumerate(data.items()) if m[a]], key=lambda x:(x[1], x[-1]))
       s.append((a, data[a].popleft()))
       m[a] -= 1
    

    输出:

    [('a', 5), ('a', 6), ('d', 6), ('a', 7), ('a', 8), ('b', 8), ('b', 8), ('a', 9)]
    

    【讨论】:

      猜你喜欢
      • 2010-12-06
      • 2012-11-01
      • 2023-03-24
      • 1970-01-01
      • 1970-01-01
      • 2014-02-04
      • 2010-10-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多