Oracle SQL 顺序连接数据
Posted
技术标签:
【中文标题】Oracle SQL 顺序连接数据【英文标题】:Oracle SQL Join Data Sequentially 【发布时间】:2017-01-06 20:16:03 【问题描述】:我正在尝试使用我的 SQL 跟踪材料的使用情况。我们的数据库中没有办法将零件用于其原始订单时的链接。一个零件在订单到达后简单地结束在一个箱子里,然后零件的使用基本上只是创建一个交易时使用的零件数量的记录。我正在尝试通过对数据求和并按顺序将其分配给订单号,将使用情况与订单号联系起来。 我的子查询让我走到了这一步。每个订单号都会在某个日期收到。然后,我根据需要等于或大于订单的 RECEIVEDATE 的 USEDATE 加入使用表记录。这样产生的数据是这样的:
| 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 将显示未完全使用。
【问题讨论】:
【参考方案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
【讨论】:
【参考方案2】:您正在寻找“先进先出”的库存会计。
正确的数据模型应该有两个表,一个用于“接收”部分,另一个用于“交付”或“使用”。每个表格应显示该订单的订单号、零件号和数量(已接收或已使用)以及时间戳或日期时间。我在下面的查询中对 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 的“当前”库存数量,可用于将来使用。同样,如果不需要,可以在外部查询中将其删除。表格的末尾可能有一行或多行这样的行。
【讨论】:
我遇到的问题是我们的使用表没有订单号,因为没有办法加一个。我相信它只是我们的糟糕设计,当零件到达时,它们只是被扔进垃圾箱。那时,零件上没有序列号或任何其他类型的跟踪。因此,当一个被订购时,它只是从一个垃圾箱中取出并发送出去,使用记录只是记录了零件编号、数量和时间戳。以上是关于Oracle SQL 顺序连接数据的主要内容,如果未能解决你的问题,请参考以下文章