英文:
split into rows by maximum value of a accumulated column
问题
我找不到如何从累积总和中分割行的方法。我有以下结果:
+---------+-----------------+---------+---------------+
|ORDER_ID | DENOM_ID | DENOM_VAL | AMOUNT | MAX_PAGE_AMOUNT |
+--------+--------+---------+---------+---------------+
| AAAAAAAA | EUR100 | 100 | 2,800,000 | 1,000,000 |
| AAAAAAAA | EUR050 | 50 | 700,000 | 1,000,000 |
| AAAAAAAA | EUR010 | 10 | 150,000 | 1,000,000 |
+--------+--------+---------+---------+---------------+
- ORDER_ID:订单号
- DENOM_ID:货币面额ID
- DENOM_VAL:真实货币价值
- AMOUNT:货币面额的总金额
- MAX_PAGE_AMOUNT:每个报告页面的最大货币金额
SQL查询应生成以下行:
+-------+--------+--------+---------+---------+----------+---------------+
| PAG_NUM | ORDER_ID | DENOM_ID | DENOM_VAL | AMOUNT | NEW_AMOUNT | MAX_PAGE_AMOUNT |
+-------+--------+--------+---------+---------+----------+---------------+
| 1 | AAAAAAAA | EUR100 | 100 | 2,800,000 | 1,000,000 | 1,000,000 |
| 2 | AAAAAAAA | EUR100 | 100 | 2,800,000 | 1,000,000 | 1,000,000 |
| 3 | AAAAAAAA | EUR100 | 100 | 2,800,000 | 800,000 | 1,000,000 |
| 3 | AAAAAAAA | EUR050 | 50 | 700,000 | 200,000 | 1,000,000 |
| 4 | AAAAAAAA | EUR050 | 50 | 700,000 | 300,000 | 1,000,000 |
| 4 | AAAAAAAA | EUR010 | 10 | 150,000 | 150,000 | 1,000,000 |
+-------+--------+--------+---------+---------+----------+---------------+
- PAG_NUM:页码
- ORDER_ID:订单号
- DENOM_ID:货币面额ID
- DENOM_VAL:真实货币价值
- AMOUNT:货币面额的总金额
- NEW_AMOUNT:不能超过每页的MAX_PAGE_AMOUNT的新总金额
- MAX_PAGE_AMOUNT:每个报告页面的最大金额
摘要:
每页的总金额不能超过MAX_PAGE_AMOUNT,当发生这种情况时,必须将AMOUNT分割成新的页面,直到不超过MAX_PAGE_AMOUNT的值。
我的当前SQL查询如下:
WITH cte_dat AS (
SELECT order_id, denom_id, denom_val, amount, max_page_amount
FROM my_table
),
cte_rec (order_id, denom_id, denom_val, amount, max_page_amount) AS (
SELECT order_id, denom_id, denom_val, amount, max_page_amount
FROM cte_dat
UNION ALL
SELECT order_id, denom_id, denom_val, amount, amount - max_page_amount AS amount
FROM cte_rec
WHERE (amount - max_page_amount) > 0
)
SELECT order_id, denom_id, denom_val, LEAST(amount, max_page_amount) AS amount, max_page_amount
FROM cte_rec
ORDER BY order_id, denom_val DESC, amount DESC
结果如下:
+--------+--------+---------+---------+----------+---------------+
| ORDER_ID | DENOM_ID | DENOM_VAL | AMOUNT | MAX_AMOUNT | MAX_PAGE_AMOUNT |
+--------+--------+---------+---------+----------+---------------+
| AAAAAAAA | EUR100 | 100 | 2,800,000 | 1,000,000 | 1,000,000 |
| AAAAAAAA | EUR100 | 100 | 2,800,000 | 1,000,000 | 1,000,000 |
| AAAAAAAA | EUR100 | 100 | 2,800,000 | 800,000 | 1,000,000 |
| AAAAAAAA | EUR050 | 50 | 700,000 | 700,000 | 1,000,000 |
| AAAAAAAA | EUR010 | 10 | 150,000 | 150,000 | 1,000,000 |
+--------+--------+---------+---------+----------+---------------+
英文:
I can't find how to split in the rows from an accumulated sum. I have the following results:
+---------+-----------------+---------+---------------+
|ORDER_ID|DENOM_ID|DENOM_VAL| AMOUNT|MAX_PAGE_AMOUNT|
+--------+--------+---------+---------+---------------+
|AAAAAAAA|EUR100 | 100|2,800,000| 1,000,000 |
|AAAAAAAA|EUR050 | 50| 700,000| 1,000,000 |
|AAAAAAAA|EUR010 | 10| 150,000| 1,000,000 |
+--------+--------+---------+---------+---------------+
- ORDER_ID: Order number
- DENOM_ID: Currency denomination ID
- DENOM_VAL: Real currency value
- AMOUNT: Total amount of currency denomination
- MAX_PAGE_AMOUNT: Max. currency per report page
The SQL query should generate the following rows:
+-------+--------+--------+---------+---------+----------+---------------+
|PAG_NUM|ORDER_ID|DENOM_ID|DENOM_VAL| AMOUNT|NEW_AMOUNT|MAX_PAGE_AMOUNT|
+-------+--------+--------+---------+---------+----------+---------------+
| 1|AAAAAAAA|EUR100 | 100|2,800,000| 1,000,000| 1,000,000|
| 2|AAAAAAAA|EUR100 | 100|2,800,000| 1,000,000| 1,000,000|
| 3|AAAAAAAA|EUR100 | 100|2,800,000| 800,000| 1,000,000|
| 3|AAAAAAAA|EUR050 | 50| 700,000| 200,000| 1,000,000|
| 4|AAAAAAAA|EUR050 | 50| 700,000| 300,000| 1,000,000|
| 4|AAAAAAAA|EUR010 | 10| 150,000| 150,000| 1,000,000|
+-------+--------+--------+---------+---------+----------+---------------+
- PAG_NUM: Page number
- ORDER_ID: Order number
- DENOM_ID: Currency denomination ID
- DENOM_VAL: Real currency value
- AMOUNT: Total amount of currency denomination
- NEW_AMOUNT: New total amount that cannot exceed MAX_PAGE_AMOUNT per page
- MAX_PAGE_AMOUNT: Max. amount by report page
Summary:
The summed amounts per page cannot exceed MAX_PAGE_AMOUNT, when that occurs AMOUNT must be divided/split in a new page until it does not exceed the value of MAX_PAGE_AMOUNT.
My current SQL is:
WITH cte_dat AS (
SELECT order_id, denom_id, denom_val, amount, max_page_amount
FROM my_table
),
cte_rec (order_id, denom_id, denom_val, amount, max_page_amount) AS (
SELECT order_id, denom_id, denom_val, amount, max_page_amount
FROM cte_dat
UNION ALL
SELECT order_id, denom_id, denom_val, amount, amount - max_page_amount AS amount
FROM cte_rec
WHERE (amount - max_page_amount) > 0
)
SELECT order_id, denom_id, denom_val, LEAST(amount, max_page_amount) AS amount, max_page_amount
FROM cte_rec
ORDER BY order_id, denom_val DESC, amount DESC
Results:
+--------+--------+---------+---------+----------+---------------+
|ORDER_ID|DENOM_ID|DENOM_VAL| AMOUNT|MAX_AMOUNT|MAX_PAGE_AMOUNT|
+--------+--------+---------+---------+----------+---------------+
|AAAAAAAA|EUR100 | 100|2,800,000| 1,000,000| 1,000,000|
|AAAAAAAA|EUR100 | 100|2,800,000| 1,000,000| 1,000,000|
|AAAAAAAA|EUR100 | 100|2,800,000| 800,000| 1,000,000|
|AAAAAAAA|EUR050 | 50| 700,000| 700,000| 1,000,000|
|AAAAAAAA|EUR010 | 10| 150,000| 150,000| 1,000,000|
+--------+--------+---------+---------+----------+---------------+
答案1
得分: 3
您可以使用分析函数生成金额的累积总数,并使用递归查询将其分割成页面:
WITH cte_rec (
order_id,
denom_id,
denom_val,
amount,
max_page_amount,
prev_total,
total,
start_page,
end_page
) AS (
SELECT order_id,
denom_id,
denom_val,
amount,
max_page_amount,
SUM(amount) OVER (ORDER BY order_id, denom_val DESC, amount DESC, ROWNUM) - amount,
SUM(amount) OVER (ORDER BY order_id, denom_val DESC, amount DESC, ROWNUM),
GREATEST(
CEIL(
(SUM(amount)
OVER (ORDER BY order_id, denom_val DESC, amount DESC, ROWNUM) - amount)
/ max_page_amount
),
1
),
CEIL(
SUM(amount) OVER (ORDER BY order_id, denom_val DESC, amount, ROWNUM)
/ max_page_amount
)
FROM my_table
UNION ALL
SELECT order_id,
denom_id,
denom_val,
amount,
max_page_amount,
prev_total,
total,
start_page + 1,
end_page
FROM cte_rec
WHERE start_page < end_page
)
SEARCH DEPTH FIRST BY order_id, denom_val DESC, amount DESC SET o_id
SELECT start_page AS page_num,
order_id,
denom_id,
denom_val,
amount,
LEAST(start_page * max_page_amount, total)
- GREATEST((start_page - 1) * max_page_amount, prev_total) AS new_amount,
max_page_amount
FROM cte_rec;
对于示例数据:
CREATE TABLE my_table (ORDER_ID, DENOM_ID, DENOM_VAL, AMOUNT, MAX_PAGE_AMOUNT) AS
SELECT 'AAAAAAAA', 'EUR100', 100, 2800000, 1000000 FROM DUAL UNION ALL
SELECT 'AAAAAAAA', 'EUR050', 50, 700000, 1000000 FROM DUAL UNION ALL
SELECT 'AAAAAAAA', 'EUR010', 10, 150000, 1000000 FROM DUAL;
输出如下:
PAGE_NUM | ORDER_ID | DENOM_ID | DENOM_VAL | AMOUNT | NEW_AMOUNT | MAX_PAGE_AMOUNT |
---|---|---|---|---|---|---|
1 | AAAAAAAA | EUR100 | 100 | 2800000 | 1000000 | 1000000 |
2 | AAAAAAAA | EUR100 | 100 | 2800000 | 1000000 | 1000000 |
3 | AAAAAAAA | EUR100 | 100 | 2800000 | 800000 | 1000000 |
3 | AAAAAAAA | EUR050 | 50 | 700000 | 200000 | 1000000 |
4 | AAAAAAAA | EUR050 | 50 | 700000 | 500000 | 1000000 |
4 | AAAAAAAA | EUR010 | 10 | 150000 | 150000 | 1000000 |
英文:
You can use an analytic function to generate the running totals for the amounts and use a recursive query to split that into pages:
WITH cte_rec (
order_id,
denom_id,
denom_val,
amount,
max_page_amount,
prev_total,
total,
start_page,
end_page
) AS (
SELECT order_id,
denom_id,
denom_val,
amount,
max_page_amount,
SUM(amount) OVER (ORDER BY order_id, denom_val DESC, amount DESC, ROWNUM) - amount,
SUM(amount) OVER (ORDER BY order_id, denom_val DESC, amount DESC, ROWNUM),
GREATEST(
CEIL(
(SUM(amount)
OVER (ORDER BY order_id, denom_val DESC, amount DESC, ROWNUM) - amount)
/ max_page_amount
),
1
),
CEIL(
SUM(amount) OVER (ORDER BY order_id, denom_val DESC, amount, ROWNUM)
/ max_page_amount
)
FROM my_table
UNION ALL
SELECT order_id,
denom_id,
denom_val,
amount,
max_page_amount,
prev_total,
total,
start_page + 1,
end_page
FROM cte_rec
WHERE start_page < end_page
)
SEARCH DEPTH FIRST BY order_id, denom_val DESC, amount DESC SET o_id
SELECT start_page AS page_num,
order_id,
denom_id,
denom_val,
amount,
LEAST(start_page * max_page_amount, total)
- GREATEST((start_page - 1) * max_page_amount, prev_total) AS new_amount,
max_page_amount
FROM cte_rec;
Which, for the sample data:
CREATE TABLE my_table (ORDER_ID, DENOM_ID, DENOM_VAL, AMOUNT, MAX_PAGE_AMOUNT) AS
SELECT 'AAAAAAAA', 'EUR100', 100, 2800000, 1000000 FROM DUAL UNION ALL
SELECT 'AAAAAAAA', 'EUR050', 50, 700000, 1000000 FROM DUAL UNION ALL
SELECT 'AAAAAAAA', 'EUR010', 10, 150000, 1000000 FROM DUAL;
Outputs:
PAGE_NUM | ORDER_ID | DENOM_ID | DENOM_VAL | AMOUNT | NEW_AMOUNT | MAX_PAGE_AMOUNT |
---|---|---|---|---|---|---|
1 | AAAAAAAA | EUR100 | 100 | 2800000 | 1000000 | 1000000 |
2 | AAAAAAAA | EUR100 | 100 | 2800000 | 1000000 | 1000000 |
3 | AAAAAAAA | EUR100 | 100 | 2800000 | 800000 | 1000000 |
3 | AAAAAAAA | EUR050 | 50 | 700000 | 200000 | 1000000 |
4 | AAAAAAAA | EUR050 | 50 | 700000 | 500000 | 1000000 |
4 | AAAAAAAA | EUR010 | 10 | 150000 | 150000 | 1000000 |
答案2
得分: 0
以下是已翻译好的内容:
使用 CONNECT BY LEVEL
根据金额除以 max_page_amount
生成所需的行数。
SELECT
order_id
, denom_id
, denom_val
, amount
, max_page_amount
FROM my_table CONNECT BY LEVEL <= CEIL(amount / max_page_amount)
WHERE PRIOR order_id = order_id
AND PRIOR denom_id = denom_id
AND PRIOR denom_val = denom_val
AND PRIOR amount = amount
AND PRIOR max_page_amount = max_page_amount
CEIL
用于确保即使除法不精确,所有行也被包括在内,而 PRIOR
关键字用于确保重复的行具有与原始行相同的值。
如果您不喜欢使用 Oracle 特定的函数,那么使用 "递归 CTE" 也可以工作:
WITH CTE
AS (
SELECT order_id, denom_id, denom_val, amount, max_page_amount, 1 AS lvl
FROM my_table
UNION ALL
SELECT order_id, denom_id, denom_val, amount, max_page_amount, lvl + 1
FROM CTE
WHERE lvl < CEIL(amount / max_page_amount)
)
SELECT
order_id
, denom_id
, denom_val
, amount
, max_page_amount
FROM CTE;
英文:
Use CONNECT BY LEVEL
to generate the necessary number of rows based on the division of amount by max_page_amount.
SELECT
order_id
, denom_id
, denom_val
, amount
, max_page_amount
FROM my_table CONNECT BY LEVEL <= CEIL(amount / max_page_amount)
WHERE PRIOR order_id = order_id
AND PRIOR denom_id = denom_id
AND PRIOR denom_val = denom_val
AND PRIOR amount = amount
AND PRIOR max_page_amount = max_page_amount
CEIL
is used to ensure that all the rows are included even if the division is not exact, and the PRIOR
keyword is used to ensure that the repeated rows have the same values as the original row.
If you prefer not to use Oracle specific functions, then using a "recursive CTE" should also work:
WITH CTE
AS (
SELECT order_id, denom_id, denom_val, amount, max_page_amount, 1 AS lvl
FROM my_table
UNION ALL
SELECT order_id, denom_id, denom_val, amount, max_page_amount, lvl + 1
FROM CTE
WHERE lvl < CEIL(amount / max_page_amount)
)
SELECT
order_id
, denom_id
, denom_val
, amount
, max_page_amount
FROM CTE;
答案3
得分: 0
这是您提供的代码段的翻译:
基于数据区间和最大页数 max_page_amount 的计算,还有另一种解决方案,可以比较在您的数据集上的性能。在这里,递归仅用于生成桶:
在区间中(intervals)作为 (
选择 d.*, lag(sum_amount,1,0) over(order by rn) 作为 start_interval, sum_amount as end_interval
从 (
选择 rownum as rn, order_id, denom_id, denom_val, amount, max_page_amount,
sum(amount) over(order by rownum) as sum_amount
从 my_table
) d
)
, maxdata 作为 (
选择 max_page_amount, sum(amount) as max_amount 从 my_table1
按 max_page_amount 分组
)
, buckets 作为 (
选择 level as bucket_id, (level-1) * max_page_amount as start_bucket, level * max_page_amount as end_bucket
从 maxdata
连接通过 (level-1) * max_page_amount < max_amount
)
选择 bucket_id as page_num, order_id, denom_id, denom_val, amount, max_page_amount,
案例当 end_interval > end_bucket
然后
最小值(max_page_amount, end_bucket - start_interval)
否则
最小值(amount, end_interval - start_bucket)
结束作为 new_page_amount
从 intervals
加入 buckets 在 start_bucket <= end_interval 和 end_bucket >= start_interval
;
请注意,我只提供了代码的翻译部分,没有回答其他问题。如果您需要进一步的翻译或解释,请告诉我。
英文:
There is another solution based on calculation of intervals on the data and buckets of max_page_amount, it could be interesting to compare the performances on your data set, here recursion is used only to generate the buckets:
with intervals as (
select d.*, lag(sum_amount,1,0) over(order by rn) as start_interval, sum_amount as end_interval
from (
select rownum as rn, order_id, denom_id, denom_val, amount, max_page_amount,
sum(amount) over(order by rownum) as sum_amount
from my_table
) d
)
, maxdata as (
select max_page_amount, sum(amount) as max_amount from my_table1
group by max_page_amount
)
, buckets as (
select level as bucket_id, (level-1) * max_page_amount as start_bucket, level * max_page_amount as end_bucket
from maxdata
connect by (level-1) * max_page_amount < max_amount
)
select bucket_id as page_num, order_id, denom_id, denom_val, amount, max_page_amount,
case when end_interval > end_bucket
then
least(max_page_amount, end_bucket - start_interval)
else
least(amount, end_interval - start_bucket)
end as new_page_amount
from intervals
join buckets on start_bucket <= end_interval and end_bucket >= start_interval
;
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论