Oracle sql 拆分行以用参考文章填充最大数量
Oracle sql split up rows to fill maxquantity with reference articles
这是一个扩展问题
假设我有一个文章列表,我想将其拆分以填充最大值包括附加文章(第 7 条),它引用其他位置:
id | ref | name | quantity | maxquantity
1 | null | name_a| 3 | 5
2 | null | name_a| 1 | 5
3 | null | name_a| 3 | 5
4 | null | name_a| 5 | 5
5 | null | name_b| 7 | 4
6 | null | name_b| 2 | 4
7 | 5 | add_1 | 14 | null
我想创建按名称分组的包,填充到最大值,保持引用关系和引用文章与引用文章的比率以获得以下内容结果:
1 | null | name_a| 3 | 5 | name_a_part1 | 3
2 | null | name_a| 1 | 5 | name_a_part1 | 1
3 | null | name_a| 3 | 5 | name_a_part1 | 1
^- sum() = maxquantity
3 | null | name_a| 3 | 5 | name_a_part2 | 2
4 | null | name_a| 5 | 5 | name_a_part2 | 3
^- sum() = maxquantity
4 | null | name_a| 5 | 5 | name_a_part3 | 2
^- sum() = maxquantity or the rest of name_a
5 | null | name_b| 7 | 4 | name_b_part1 | 4
^- sum() = maxquantity
5 | null | name_b| 7 | 4 | name_b_part2 | 3
6 | null | name_b| 2 | 4 | name_b_part2 | 1
^- sum() = maxquantity
6 | null | name_b| 2 | 4 | name_b_part3 | 1
^- sum() = maxquantity or the rest of name_b
7 | 5 | add_1| 14| null | name_b_part1 | 8
7 | 5 | add_1| 14| null | name_b_part2 | 6
pos5 与 pos7 的比率是 1:2
最终 bin 的名称或编号应在 referenced-articles 和 referencing-articles 之间匹配
我设法解决了这个问题。
通过
创建table
CREATE TABLE articles (pos, ref_pos, article, quantity, maxquantity ) AS
SELECT 0, NULL, 'prod1', 3, 6 FROM DUAL UNION ALL
SELECT 1, NULL, 'prod1', 3, 6 FROM DUAL UNION ALL
SELECT 2, NULL, 'prod1', 8, 6 FROM DUAL UNION ALL
SELECT 7, 2, 'addon_for_pos2', 16, NULL FROM DUAL
这 sql 将得到正确的结果:
WITH split_bins (pos, ref_pos, article, quantity, maxquantity, bin_tag, bin_tag2, effective_quantity, prev_quantity,effective_name, ratio) AS (
-- ################### the first static iteration
SELECT pos,
ref_pos,
article,
quantity,
-- ################### calculate the max-quantity
COALESCE(
maxquantity, CONNECT_BY_ROOT maxquantity * quantity / CONNECT_BY_ROOT quantity
) AS maxquantity,
-- ################### calculate the bin_tag for grouping
FLOOR(
COALESCE(
SUM(quantity) OVER (
PARTITION BY article
ORDER BY pos
ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING
),
0
)
/ COALESCE(
maxquantity, CONNECT_BY_ROOT maxquantity * quantity / CONNECT_BY_ROOT quantity
)
) + 1 as bin_tag,
-- ################### calculate the bin_tag for grouping supplements to correct bin
FLOOR(
COALESCE(
SUM(quantity) OVER (
PARTITION BY article, pos
ORDER BY pos
ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING
),
0
)
/ COALESCE(
maxquantity, CONNECT_BY_ROOT maxquantity * quantity / CONNECT_BY_ROOT quantity
)
) + 1 as bin_tag2,
-- ################### calculate the effective quantity
LEAST(
COALESCE(
maxquantity, CONNECT_BY_ROOT maxquantity * quantity / CONNECT_BY_ROOT quantity
)
- MOD(
COALESCE(
SUM(quantity) OVER (
PARTITION BY article
ORDER BY pos
ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING
),
0
),
COALESCE(
maxquantity, CONNECT_BY_ROOT maxquantity * quantity / CONNECT_BY_ROOT quantity
)
),
quantity
) AS effective_quantity,
-- ################### previously used quantity (start with zero)
0 AS prev_quantity,
-- ################### propagate the referenced article to the referencing articles
CONNECT_BY_ROOT article AS effective_name,
-- ################### calculate the ratio of main articles and addons (just dev)
quantity / CONNECT_BY_ROOT quantity AS ratio
FROM
articles START WITH ref_pos IS NULL CONNECT BY PRIOR pos = ref_pos
-- ################### the 2nd to n iteration
UNION ALL
--(pos, ref_pos, article, quantity, maxquantity, bin_tag, effective_quantity, prev_quantity,effective_name, ratio)
SELECT pos,
ref_pos,
article,
quantity,
maxquantity,
-- ################### increase the identifier
bin_tag + 1 as bin_tag,
bin_tag2 + 1 as bin_tag2,
-- ################### calculate the current effective_quantity
LEAST(
quantity - prev_quantity - effective_quantity,
maxquantity
) as effective_quantity,
-- ################### calculate the prev_quantity for next iteration
prev_quantity + effective_quantity as prev_quantity,
effective_name,
ratio
FROM split_bins
WHERE prev_quantity + effective_quantity < quantity
)
-- ################### final select data from with-clause
SELECT pos, ref_pos, article, quantity, maxquantity, bin_tag, bin_tag2,effective_quantity, prev_quantity,effective_name, ratio,effective_name||'_limit_'||connect_by_root bin_tag as id
FROM split_bins START WITH ref_pos IS NULL CONNECT BY PRIOR pos = ref_pos and PRIOR bin_tag2=bin_tag2
order by pos, bin_tag;
这是一个扩展问题
假设我有一个文章列表,我想将其拆分以填充最大值包括附加文章(第 7 条),它引用其他位置:
id | ref | name | quantity | maxquantity
1 | null | name_a| 3 | 5
2 | null | name_a| 1 | 5
3 | null | name_a| 3 | 5
4 | null | name_a| 5 | 5
5 | null | name_b| 7 | 4
6 | null | name_b| 2 | 4
7 | 5 | add_1 | 14 | null
我想创建按名称分组的包,填充到最大值,保持引用关系和引用文章与引用文章的比率以获得以下内容结果:
1 | null | name_a| 3 | 5 | name_a_part1 | 3
2 | null | name_a| 1 | 5 | name_a_part1 | 1
3 | null | name_a| 3 | 5 | name_a_part1 | 1
^- sum() = maxquantity
3 | null | name_a| 3 | 5 | name_a_part2 | 2
4 | null | name_a| 5 | 5 | name_a_part2 | 3
^- sum() = maxquantity
4 | null | name_a| 5 | 5 | name_a_part3 | 2
^- sum() = maxquantity or the rest of name_a
5 | null | name_b| 7 | 4 | name_b_part1 | 4
^- sum() = maxquantity
5 | null | name_b| 7 | 4 | name_b_part2 | 3
6 | null | name_b| 2 | 4 | name_b_part2 | 1
^- sum() = maxquantity
6 | null | name_b| 2 | 4 | name_b_part3 | 1
^- sum() = maxquantity or the rest of name_b
7 | 5 | add_1| 14| null | name_b_part1 | 8
7 | 5 | add_1| 14| null | name_b_part2 | 6
pos5 与 pos7 的比率是 1:2
最终 bin 的名称或编号应在 referenced-articles 和 referencing-articles 之间匹配
我设法解决了这个问题。
通过
创建tableCREATE TABLE articles (pos, ref_pos, article, quantity, maxquantity ) AS
SELECT 0, NULL, 'prod1', 3, 6 FROM DUAL UNION ALL
SELECT 1, NULL, 'prod1', 3, 6 FROM DUAL UNION ALL
SELECT 2, NULL, 'prod1', 8, 6 FROM DUAL UNION ALL
SELECT 7, 2, 'addon_for_pos2', 16, NULL FROM DUAL
这 sql 将得到正确的结果:
WITH split_bins (pos, ref_pos, article, quantity, maxquantity, bin_tag, bin_tag2, effective_quantity, prev_quantity,effective_name, ratio) AS (
-- ################### the first static iteration
SELECT pos,
ref_pos,
article,
quantity,
-- ################### calculate the max-quantity
COALESCE(
maxquantity, CONNECT_BY_ROOT maxquantity * quantity / CONNECT_BY_ROOT quantity
) AS maxquantity,
-- ################### calculate the bin_tag for grouping
FLOOR(
COALESCE(
SUM(quantity) OVER (
PARTITION BY article
ORDER BY pos
ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING
),
0
)
/ COALESCE(
maxquantity, CONNECT_BY_ROOT maxquantity * quantity / CONNECT_BY_ROOT quantity
)
) + 1 as bin_tag,
-- ################### calculate the bin_tag for grouping supplements to correct bin
FLOOR(
COALESCE(
SUM(quantity) OVER (
PARTITION BY article, pos
ORDER BY pos
ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING
),
0
)
/ COALESCE(
maxquantity, CONNECT_BY_ROOT maxquantity * quantity / CONNECT_BY_ROOT quantity
)
) + 1 as bin_tag2,
-- ################### calculate the effective quantity
LEAST(
COALESCE(
maxquantity, CONNECT_BY_ROOT maxquantity * quantity / CONNECT_BY_ROOT quantity
)
- MOD(
COALESCE(
SUM(quantity) OVER (
PARTITION BY article
ORDER BY pos
ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING
),
0
),
COALESCE(
maxquantity, CONNECT_BY_ROOT maxquantity * quantity / CONNECT_BY_ROOT quantity
)
),
quantity
) AS effective_quantity,
-- ################### previously used quantity (start with zero)
0 AS prev_quantity,
-- ################### propagate the referenced article to the referencing articles
CONNECT_BY_ROOT article AS effective_name,
-- ################### calculate the ratio of main articles and addons (just dev)
quantity / CONNECT_BY_ROOT quantity AS ratio
FROM
articles START WITH ref_pos IS NULL CONNECT BY PRIOR pos = ref_pos
-- ################### the 2nd to n iteration
UNION ALL
--(pos, ref_pos, article, quantity, maxquantity, bin_tag, effective_quantity, prev_quantity,effective_name, ratio)
SELECT pos,
ref_pos,
article,
quantity,
maxquantity,
-- ################### increase the identifier
bin_tag + 1 as bin_tag,
bin_tag2 + 1 as bin_tag2,
-- ################### calculate the current effective_quantity
LEAST(
quantity - prev_quantity - effective_quantity,
maxquantity
) as effective_quantity,
-- ################### calculate the prev_quantity for next iteration
prev_quantity + effective_quantity as prev_quantity,
effective_name,
ratio
FROM split_bins
WHERE prev_quantity + effective_quantity < quantity
)
-- ################### final select data from with-clause
SELECT pos, ref_pos, article, quantity, maxquantity, bin_tag, bin_tag2,effective_quantity, prev_quantity,effective_name, ratio,effective_name||'_limit_'||connect_by_root bin_tag as id
FROM split_bins START WITH ref_pos IS NULL CONNECT BY PRIOR pos = ref_pos and PRIOR bin_tag2=bin_tag2
order by pos, bin_tag;