Oracle SQL按顺序连接数据

时间:2017-01-06 20:16:03

标签: sql oracle

我正在尝试使用SQL跟踪材料的使用情况。当部件用于最初来自的订单时,我们的数据库中无法链接。在订单到达之后,零件简单地终止于仓中,然后零件的使用基本上只创建了在交易时使用的零件数量的记录。我试图尽可能地通过对数据求和并依次将其分配给订单号来将使用情况链接到订单号。 我的子查询让我到目前为止。每个订单号都是在一个日期收到的。然后我根据USEDATE加入使用表记录,需要等于或大于订单的RECEIVEDATE。由此产生的数据是这样的:

| ORDERNUM |  PARTNUM |       RECEIVEDATE       |  ORDERQTY |  USEQTY |        USEDATE         |
|----------|----------|-------------------------|-----------|---------|------------------------|
|     4412 |  E1125   |  10/26/2016 1:32:25 PM  |         1 |       1 |  11/18/2016 1:40:55 PM |
|     4412 |  E1125   |  10/26/2016 1:32:25 PM  |         1 |       3 |  12/26/2016 2:19:32 PM |
|     4412 |  E1125   |  10/26/2016 1:32:25 PM  |         1 |       1 |  1/3/2017 8:31:21 AM   |
|     4111 |  E1125   |  10/28/2016 2:54:13 PM  |         1 |       1 |  11/18/2016 1:40:55 PM |
|     4111 |  E1125   |  10/28/2016 2:54:13 PM  |         1 |       3 |  12/26/2016 2:19:32 PM |
|     4111 |  E1125   |  10/28/2016 2:54:13 PM  |         1 |       1 |  1/3/2017 8:31:21 AM   |
|     0393 |  E1125   |  12/22/2016 11:52:04 AM |         3 |       3 |  12/26/2016 2:19:32 PM |
|     0393 |  E1125   |  12/22/2016 11:52:04 AM |         3 |       1 |  1/3/2017 8:31:21 AM   |
|     7812 |  E1125   |  12/27/2016 10:56:01 AM |         1 |       1 |  1/3/2017 8:31:21 AM   |
|     1191 |  E1125   |  1/5/2017 1:12:01 PM    |         2 |       0 |  null                  |

上述部分的查询如下:

SELECT 
B.*, 
NVL(B2.QTY, ‘0’) USEQTY
B2.USEDATE USEDATE
FROM <<Sub Query B>>
LEFT JOIN USETABLE B2 ON B.PARTNUM = B2.PARTNUM AND B2.USEDATE >= B.RECEIVEDATE

我的最终目标是顺序加入USEQTY记录,直到他们填写足够的ORDERQTY。我还需要添加一个ORDERUSE列,该列表示USEQTY列中实际应用于该记录的QTY。不确定如何更好地说这个,所以这里是基于上表我需要发生的例子:

| ORDERNUM |  PARTNUM |       RECEIVEDATE       |  ORDERQTY |  USEQTY |         USEDATE        |  ORDERUSE |
|----------|----------|-------------------------|-----------|---------|------------------------|-----------|
|     4412 |  E1125   |  10/26/2016 1:32:25 PM  |         1 |       1 |  11/18/2016 1:40:55 PM |         1 |
|     4111 |  E1125   |  10/28/2016 2:54:13 PM  |         1 |       3 |  12/26/2016 2:19:32 PM |         1 |
|     0393 |  E1125   |  12/22/2016 11:52:04 AM |         3 |       2 |  12/26/2016 2:19:32 PM |         2 |
|     0393 |  E1125   |  12/22/2016 11:52:04 AM |         3 |       1 |  1/3/2017 8:31:21 AM   |         1 |
|     7812 |  E1125   |  12/27/2016 10:56:01 AM |         1 |       0 |  null                  |         0 |
|     1191 |  E1125   |  1/5/2017 1:12:01 PM    |         2 |       0 |  null                  |         0 |

如果我可以获取查询以提取上述信息,那么我将能够将记录组合​​在一起并汇总ORDERUSE列,这将获取我需要知道哪些订单已被使用以及哪些没有使用的信息已被充分利用。因此,在上面的示例中,如果我要对每个ORDERNUM的ORDERUSE列求和,则订单4412,4111,0393都将显示完全使用。订单7812,1191将显示未被充分使用。

2 个答案:

答案 0 :(得分:1)

如果我正确读取此信息,您需要确定已使用了多少部件。在您的示例中,您看起来有5次使用,5次订单共计8个部分,并且已使用以下订单。

  • 4412 - 一部分 - 一部分使用
  • 4111 - 一部分 - 一部分使用
  • 7812 - 一部分 - 一部分使用
  • 0393 - 三 零件 - 两个用过

经过一段时间的黑客攻击后,我提出了以下SQL。不确定这是否适用于您的样本数据之外,因为这是我用来测试的唯一内容,而且我不是专家。

WITH data 
 AS (SELECT * 
     FROM   (SELECT * 
             FROM   sub_b1 
                    join (SELECT ROWNUM rn 
                          FROM   dual 
                          CONNECT BY LEVEL < 15) a 
                      ON a.rn <= sub_b1.orderqty 
             ORDER  BY receivedate) 
     WHERE  ROWNUM <= (SELECT SUM(useqty) 
                       FROM   sub_b2)) 
SELECT sub_b1.ordernum, 
   partnum, 
   receivedate, 
   orderqty, 
   usage 
FROM   sub_b1 
   join (SELECT ordernum, 
                Max(rn) AS usage 
         FROM   data 
         GROUP  BY ordernum) b 
     ON sub_b1.ordernum = b.ordernum 

答案 1 :(得分:0)

您正在寻找“FIFO”库存会计。

正确的数据模型应该有两个表,一个用于“已接收”部分,另一个用于“已交付”或“已使用”。每个表应显示该订单的订单号,部件号和数量(已接收或已使用),以及时间戳或日期时间。我在下面的查询中对CTE进行了建模,但在您的业务中,它们应该是两个单独的表。此外,触发器或类似物应强制执行约束,即在库存可用之前不能使用该部件(即:对于每个部件ID,自开始以来使用的总量,在任何时间点,不应超过总量自成立以来,也在同一时间点收到)。事实上,我假设两个输入表确实满足这个条件,我不在解决方案中检查它。

输出显示按时间戳使用的数量的时间线,匹配每个part_id的“已接收”和“已交付”(已使用)数量。在示例数据中,我说明了单个part_id,但查询将使用多个part_id和订单(包括已接收和已交付或已使用的订单),其中包含具有不同数量的多个部分(部分ID)。

with
     received  ( order_id, part_id, ts, qty ) as (
       select '0030', '11A4', timestamp '2015-03-18 15:00:33', 20 from dual union all
       select '0032', '11A4', timestamp '2015-03-22 15:00:33', 13 from dual union all
       select '0034', '11A4', timestamp '2015-03-24 10:00:33', 18 from dual union all
       select '0036', '11A4', timestamp '2015-04-01 15:00:33', 25 from dual
     ),
     delivered ( order_id, part_id, ts, qty ) as (
       select '1200', '11A4', timestamp '2015-03-18 16:30:00', 14 from dual union all
       select '1210', '11A4', timestamp '2015-03-23 10:30:00',  8 from dual union all
       select '1220', '11A4', timestamp '2015-03-23 11:30:00',  7 from dual union all
       select '1230', '11A4', timestamp '2015-03-23 11:30:00',  4 from dual union all
       select '1240', '11A4', timestamp '2015-03-26 15:00:33',  1 from dual union all
       select '1250', '11A4', timestamp '2015-03-26 16:45:11',  3 from dual union all
       select '1260', '11A4', timestamp '2015-03-27 10:00:33',  2 from dual union all
       select '1270', '11A4', timestamp '2015-04-03 15:00:33', 16 from dual
     ),

(测试数据结束; SQL查询从下面开始 - 只需在顶部添加单词WITH

-- with
     combined ( part_id, rec_ord, rec_ts, rec_sum, del_ord, del_ts, del_sum) as (
       select part_id, order_id, ts,
              sum(qty) over (partition by part_id order by ts, order_id), 
              null, cast(null as date), cast(null as number)
         from received
       union all
       select part_id, null, cast(null as date), cast(null as number),
              order_id, ts,
              sum(qty) over (partition by part_id order by ts, order_id)
         from delivered
     ),
     prep ( part_id, rec_ord, del_ord, del_ts, qty_sum ) as (
       select part_id, rec_ord, del_ord, del_ts, coalesce(rec_sum, del_sum)
       from   combined 
     ) 
select   part_id,
         last_value(rec_ord ignore nulls) over (partition by part_id
                                                order by qty_sum desc) as rec_ord,
         last_value(del_ord ignore nulls) over (partition by part_id
                                                order by qty_sum desc) as del_ord,
         last_value(del_ts  ignore nulls) over (partition by part_id
                                                order by qty_sum desc) as used_date,
         qty_sum - lag(qty_sum, 1, 0) over (partition by part_id
                                            order by qty_sum, del_ts)  as used_qty
from     prep
order by qty_sum
;

<强>输出

PART_ID REC_ORD DEL_ORD USED_DATE                             USED_QTY
------- ------- ------- ----------------------------------- ----------
11A4    0030    1200    18-MAR-15 04.30.00.000000000 PM             14
11A4    0030    1210    23-MAR-15 10.30.00.000000000 AM              6
11A4    0032    1210    23-MAR-15 10.30.00.000000000 AM              2
11A4    0032    1220    23-MAR-15 11.30.00.000000000 AM              7
11A4    0032    1230    23-MAR-15 11.30.00.000000000 AM              4
11A4    0032    1230    23-MAR-15 11.30.00.000000000 AM              0
11A4    0034    1240    26-MAR-15 03.00.33.000000000 PM              1
11A4    0034    1250    26-MAR-15 04.45.11.000000000 PM              3
11A4    0034    1260    27-MAR-15 10.00.33.000000000 AM              2
11A4    0034    1270    03-APR-15 03.00.33.000000000 PM             12
11A4    0036    1270    03-APR-15 03.00.33.000000000 PM              4
11A4    0036                                                        21

12 rows selected.

备注 :( 1)如果累计使用数量与累计接收数量完全匹配,则需要小心。所有行必须包含在所有中间结果中,否则输出中会出现错误数据;但这可能会导致(如上面的输出中所示)几行中“使用数量”为0.取决于此输出的消耗方式(进一步处理,报告等),这些行可能会留下原样,或者它们可能会在条件为where used_qty > 0的其他外部查询中被丢弃。

(2)最后一行显示的数量为21,没有used_date而没有del_ord。事实上,这是两个表中最后一个日期的part_id的“当前”库存数量 - 可供将来使用。同样,如果不需要,可以在外部查询中删除它。在表的末尾可能有一行或多行。