0

甲骨文 SQL

示例 950/100 该表应该能够填充如下

  1. 100
  2. 100
  3. 100
  4. 100
  5. 100
  6. 100
  7. 100
  8. 100
  9. 100
  10. 50

尝试过 CONNECT BY LEVEL ,但是使用大量数据存储表似乎需要很长时间。还有其他替代方法吗?谢谢 !

4

2 回答 2

1

One approach which is worth a try is to determine the highest number of rows you may need for any input value, then to generate rows (with connect by or by any other means) just once, and then use a join to this "helper" table to generate the rows. This approach reads the base data twice, but I assume that's not the big bottleneck in this problem. In any case - worth a try.

Note that the solution also minimizes the number of arithmetic operations - it compares "row number" to the ratio of value to divisor for each row, but otherwise the output value is just the divisor in most cases.

with
  h (rn) as (
    select  level
    from    dual
    connect by level <= (select max(ceil(value/divisor)) from table_name)
  )
select tn.id, tn.value, tn.divisor, h.rn,
       case when h.rn <= tn.value/tn.divisor 
            then tn.divisor else mod(tn.value, tn.divisor) end as split_value
from   table_name tn join h on h.rn <= ceil(tn.value/tn.divisor)
order  by tn.id, h.rn
;

Which, for the data below, produces the output shown at the end. Note that I assumed there is an id column too, as primary key; in the query, I only need that to get a proper order by clause. If ordering is not needed, you don't need such an id (although you probably have it already, as an invoice number, loan number, or similar). You can also use rowid instead of id, if the only use is in the order by clause.

Sample data:

create table table_name (id, value, divisor) as
  select 2301, 450, 100 from dual union all
  select 2302, 2.3, 0.5 from dual union all
  select 2303, 300, 100 from dual union all
  select 2304,   8,  20 from dual union all
  select 2305, 150, 150 from dual
;

Output from the query, using this sample data:

        ID      VALUE    DIVISOR         RN SPLIT_VALUE
---------- ---------- ---------- ---------- -----------
      2301        450        100          1         100
      2301        450        100          2         100
      2301        450        100          3         100
      2301        450        100          4         100
      2301        450        100          5          50
      2302        2.3         .5          1          .5
      2302        2.3         .5          2          .5
      2302        2.3         .5          3          .5
      2302        2.3         .5          4          .5
      2302        2.3         .5          5          .3
      2303        300        100          1         100
      2303        300        100          2         100
      2303        300        100          3         100
      2304          8         20          1           8
      2305        150        150          1         150
于 2021-06-17T20:03:23.173 回答
1

您可以使用递归子查询因式分解子句:

WITH data ( rn, value, remainder, divisor ) AS (
  SELECT ROWNUM, value, value, divisor FROM table_name
UNION ALL
  SELECT rn, value, remainder - divisor, divisor FROM data WHERE remainder > divisor
)
SEARCH DEPTH FIRST BY rn SET rn_order
SELECT value, divisor, LEAST( remainder, divisor ) AS split_value
FROM   data;

或者,从 Oracle 12 开始,分层查询:

SELECT *
FROM   table_name t
       CROSS APPLY (
         SELECT LEAST( t.divisor, t.value - (LEVEL - 1) * t.divisor ) AS split_value
         FROM   DUAL
         CONNECT BY LEVEL <= CEIL(t.value/t.divisor)
       )

其中,对于样本数据:

CREATE TABLE table_name ( value, divisor ) AS
SELECT 950, 100 FROM DUAL UNION ALL
SELECT 2.4, 0.5 FROM DUAL

两个输出:

价值 除数 SPLIT_VALUE
950 100 100
950 100 100
950 100 100
950 100 100
950 100 100
950 100 100
950 100 100
950 100 100
950 100 100
950 100 50
2.4 0.5 0.5
2.4 0.5 0.5
2.4 0.5 0.5
2.4 0.5 0.5
2.4 0.5 0.4

db<>在这里摆弄

于 2021-06-17T18:57:53.453 回答