基于其他表分组编号

时间:2016-10-07 08:20:52

标签: sql oracle

我有一个挑战,我必须建立一些查询,我对如何开始有点迷失。我想我可能需要使用分区来实现这一点,但不确定他们的方式。 如果有人可以与我分享知识,请在此处发帖:)

首先抱歉让人感到困惑,但老实说不知道怎么用一行描述:(

问题是我有两张桌子:

广告

ITEM    QTY    PRIORITY
-----------------------------
ITEM1   10     1
ITEM1   5      2
ITEM1   4      3
ITEM1   7      4
ITEM2   4      1
ITEM2   19     2

LIST

ITEM       QTY
-----------------
ITEM1      17
ITEM2      13

我需要实现的逻辑是表LIST从INVENTORY表中删除了数量。但它必须按项目执行并删除优先级中的数量。 例如:

在LIST表中,我们有ITEM1 = 17 这意味着我们需要按照优先顺序删除Inventory表中的这个数量。

  1. 首先从第一优先级中删除(qty = 10 - 10 - >我们仍然有7个来自LIST表)
  2. 然后从第二优先级中移除(qty = 5 - 5 - >我们仍然有2个来自LIST表)
  3. 然后从第三优先级删除(qty = 4 - 2 !!! - >我们只剩下LIST表中的2个)
  4. 因此ITEM1的结果如下:

    ITEM    QTY    PRIORITY
    -----------------------------
    ITEM1   0      1
    ITEM1   0      2
    ITEM1   2      3
    ITEM1   7      4
    

    如果将整个逻辑应用于所有项目,则生成的查询应返回如下内容:

    ITEM    QTY    PRIORITY
    -----------------------------
    ITEM1   0      1
    ITEM1   0      2
    ITEM1   2      3
    ITEM1   7      4
    ITEM2   0      1
    ITEM2   10     2
    

    任何人都知道如何处理这个问题?

3 个答案:

答案 0 :(得分:5)

Oracle安装程序

CREATE TABLE inventory ( item, qty, priority ) AS
SELECT 'ITEM1', 10, 1 FROM DUAL UNION ALL
SELECT 'ITEM1',  5, 2 FROM DUAL UNION ALL
SELECT 'ITEM1',  4, 3 FROM DUAL UNION ALL
SELECT 'ITEM1',  7, 4 FROM DUAL UNION ALL
SELECT 'ITEM2',  4, 1 FROM DUAL UNION ALL
SELECT 'ITEM2', 19, 2 FROM DUAL;

CREATE TABLE list ( item, qty ) AS
SELECT 'ITEM1', 17 FROM DUAL UNION ALL
SELECT 'ITEM2', 13 FROM DUAL;

<强>查询

MERGE INTO inventory dst
USING (
  SELECT i.item,
         LEAST(
           GREATEST(
             SUM( i.qty ) OVER ( PARTITION BY i.item ORDER BY i.priority )
               - COALESCE( l.qty, 0 ),
             0
           ),
           i.qty
         ) AS qty,
         i.priority
  FROM   inventory i
         LEFT OUTER JOIN
         list l
         ON ( i.item = l.item )
) src
ON ( src.item = dst.item AND src.priority = dst.priority )
WHEN MATCHED THEN
  UPDATE SET qty = src.qty;

<强>输出

SELECT * FROM inventory;

ITEM  QTY PRIORITY
----- --- --------
ITEM1   0        1
ITEM1   0        2
ITEM1   2        3
ITEM1   7        4
ITEM2   0        1
ITEM2  10        2

答案 1 :(得分:2)

这可以通过明智地使用分析函数来计算运行总和,并将剩余的数量从上一行中删除来解决,如下所示:

WITH inventory AS (SELECT 'ITEM1' item, 10 qty, 1 priority FROM dual UNION ALL
                   SELECT 'ITEM1' item, 5 qty, 2 priority FROM dual UNION ALL
                   SELECT 'ITEM1' item, 4 qty, 3 priority FROM dual UNION ALL
                   SELECT 'ITEM1' item, 7 qty, 4 priority FROM dual UNION ALL
                   SELECT 'ITEM2' item, 4 qty, 1 priority FROM dual UNION ALL
                   SELECT 'ITEM2' item, 19 qty, 2 priority FROM dual),
          LIST AS (SELECT 'ITEM1' item, 17 qty FROM dual UNION ALL
                   SELECT 'ITEM2' item, 13 qty FROM dual),
-- end of mimicking your two tables; you would not need to do the above
-- see below for the main query
   interim_res AS (SELECT inv.item,
                          inv.qty,
                          inv.priority,
                          l.qty qty_to_del,
                          l.qty - SUM(inv.qty) OVER (PARTITION BY inv.item ORDER BY inv.priority) qty_left_to_del
                   FROM   inventory inv
                          INNER JOIN LIST l ON inv.item = l.item),
     final_res AS (SELECT item,
                          qty,
                          priority,
                          qty_to_del,
                          qty_left_to_del,
                          LAG(qty_left_to_del, 1, qty_to_del) OVER (PARTITION BY item ORDER BY priority) qty_to_del_from_current_qty
                   FROM   interim_res)
SELECT item,
       qty old_qty,
       CASE WHEN qty_to_del_from_current_qty >= qty 
                 THEN 0
            WHEN qty_to_del_from_current_qty > 0
                 THEN qty - qty_to_del_from_current_qty
            ELSE qty
       END new_qty,
       priority
FROM   final_res;

ITEM     OLD_QTY    NEW_QTY   PRIORITY
----- ---------- ---------- ----------
ITEM1         10          0          1
ITEM1          5          0          2
ITEM1          4          2          3
ITEM1          7          7          4
ITEM2          4          0          1
ITEM2         19         10          2

为了解决您的问题,首先我在库存表中,在每个项目和优先级顺序中创建了数量的运行总和。然后我们可以使用它从items表中的qty中删除,以找出我们剩下多少从下一个qty中删除(忽略我们可以得到负值的事实)。

一旦我们有了这个,接下来我们需要将要删除的数量与前一行相关联 - 我们使用LAG()来执行此操作 - 对于第一行,我们将其默认为完整的items.qty(这就是第三个参数的含义。)

(注意我把这个计算放在一个单独的子查询中,这样我们就不必在整个地方重复LAG()函数;我们可以将它称为最终外部查询中的列别名。你可以将final_res子查询和外部查询合并为一个,如果你不介意拥有所有的LAG()!)

一旦我们知道要从items.qty中删除的值,我们知道我们要采取以下三种行动之一:

  1. 删除完整的数量 - 即。 qty_to_delete&gt; = items.qty。这将导致数量为0
  2. 部分数量被删除 - 即。我们有一个非负的qty_to_delete,它小于items.qty。在这种情况下,我们可以简单地执行items.qty - qty_to_delete。
  3. 最后,我们有0或负数要删除,这在我们的场景中是无效状态,因此我们不需要从items.qty中删除任何内容。
  4. 最后,要更新你的表,我会使用MERGE。假设在库存表中,(item,priority)是唯一键,以下应该起作用:

    MERGE INTO items tgt
      USING (WITH interim_res AS (SELECT inv.item,
                                         inv.qty,
                                         inv.priority,
                                         l.qty qty_to_del,
                                         l.qty - SUM(inv.qty) OVER (PARTITION BY inv.item ORDER BY inv.priority) qty_left_to_del
                                  FROM   inventory inv
                                         INNER JOIN LIST l ON inv.item = l.item),
                    final_res AS (SELECT item,
                                         qty,
                                         priority,
                                         qty_to_del,
                                         qty_left_to_del,
                                         LAG(qty_left_to_del, 1, qty_to_del) OVER (PARTITION BY item ORDER BY priority) qty_to_del_from_current_qty
                                  FROM   interim_res)
             SELECT item,
                    qty old_qty,
                    CASE WHEN qty_to_del_from_current_qty >= qty 
                              THEN 0
                         WHEN qty_to_del_from_current_qty > 0
                              THEN qty - qty_to_del_from_current_qty
                         ELSE qty
                    END new_qty,
                    priority
             FROM   final_res) src
    ON (tgt.item = src.item AND tgt.priority = src.priority)
    WHEN MATCHED THEN
      UPDATE SET tgt.qty = src.new_qty
      WHERE tgt.qty != src.new_qty;
    

答案 2 :(得分:1)

我不是oracle的专家,但看起来你需要累计金额(总计)。请参阅herehere

SELECT item, 
       priority,
       qty,
       SUM(qty) OVER 
              (ORDER BY priority RANGE UNBOUNDED PRECEDING) c_qty
FROM inventory

我们将查询标记为sub

然后你可以使用

select
  list.*
  case when sub.c_qty<list.qty then 0 else list.qty-sub.c_qty
from list
     inner join sub on list.item=sub.item