SQL,ORACLE:使用不同的值更新列的值

时间:2016-08-16 12:57:57

标签: sql oracle

我搜索了很多,但还没找到我的问题的答案。

所以,我必须在不同的表中生成大量数据(数百万行),这个脚本应该快速。 现在让我们来谈谈3个特定的表,其中有id行:

  • 在表格所有者中,id从10000开始,递增1(带序列)
  • 在表汽车中,id从10000000开始,递增1(带序列)。


在第三个表格中,名为所有权,我必须"合并"这些ID具有一些特定的费率:

  • 50%的车主有1辆车
  • 其余车主中有20%拥有2辆车
  • 其余10-10-10%将有3辆,4辆和5辆汽车


重要事项:

  • 所有者汽车表格的说明:费率:对于100个单位所有者,将生成210个单位汽车,并且在所有权表格中汽车将是独一无二的,因此这张表中也有210行
  • 首先所有者,然后生成汽车
  • 然后我在所有权表中插入一些值"来自"的汽车



注意:以下是我如何将行生成为汽车所有者类似)
(它将生成v_custom_unit件行,此单位是根据我的费率计算的给出几行之前(对于100个单位车主,将生成210个单位车辆和210个单位所有权),然后我使用for循环来乘以行):

insert /*+ APPEND */ into Cars(
    carId
  , carType
  , ...
)
select /*+ PARALLEL */
    seq_carid.nextval as carId
  , REGEXP_SUBSTR( 'Suziki,Toyota,Subaru,Saab,Hyundai,Opel,Volkswagen', '([^,]+)', 1, ROUND(DBMS_RANDOM.VALUE(1,7)) ) as carType
  , ...
from dual
connect by level <= v_custom_unit;

乘法是这样的:

FOR i in 1..v_forSteps LOOP

    EXECUTE IMMEDIATE '
      insert /*+ APPEND */ into Cars (
          carId,
        , carType,
        , ...
      )
      SELECT /*+ PARALLEL */
          seq_carid.nextval as carId,
        , carType
        , ...
      FROM Cars
      WHERE ROWNUM <= ' || v_custom_unit;

      COMMIT;

END LOOP;

下一步是生成所有权行:

insert /*+ APPEND */ into Ownership (
     ownerId
   , carId
   , date_bought
)
select /*+ PARALLEL */
     1
   , c.carId
   , some_random_date as date_bought
from Cars c;

我的问题出现了:每辆车都在所有权中,ownerId = 1。

我的问题是:如何在一次更新中更新具有不同所有者值的所有权表(并且可能维持费率(50%-20%-10%-10%-10) %))吗

2 个答案:

答案 0 :(得分:0)

其中一种方法:

insert into ownership (ownerid, carid, bought)
  with t(oid, cid, cnt) as ( 
    select 1, 1, 1 from dual
    union all 
    select case when oid <= 5 
                     or oid <=  7 and cnt >= 2 
                     or oid <=  8 and cnt >= 3 
                     or oid <=  9 and cnt >= 4 
                     or oid <= 10 and cnt >= 5 then oid + 1
                else oid 
           end, 
           cid + 1, 
           case when oid <=  5 
                     or oid <=  7 and cnt >= 2 
                     or oid <=  8 and cnt >= 3 
                     or oid <=  9 and cnt >= 4 
                     or oid <= 10 and cnt >= 5 then 1
                else cnt + 1 
           end
    from t where cid < 21) 
  select oid, cid, trunc(sysdate) - round(dbms_random.value * 1000) from t

这是10个车主和21辆车的演示。不确定效率,但这只是一个递归查询。需要Oracle 11g。

测试表和输出:

create table ownership (carid number(6), ownerid number(6), bought date);

  CARID OWNERID BOUGHT
------- ------- -----------
      1       1 2013-12-29 -- one car
      2       2 2015-12-16
      3       3 2014-04-04
      4       4 2013-12-17
      5       5 2013-11-20
      6       6 2014-04-04 -- two cars
      7       6 2015-09-05
      8       7 2013-12-19
      9       7 2016-01-02
     10       8 2015-08-22 -- three 
     11       8 2014-03-05
     12       8 2016-07-14
     13       9 2015-09-02 -- four 
     14       9 2015-08-28
     15       9 2015-06-04
     16       9 2014-04-20
     17      10 2016-08-07 -- five 
     18      10 2015-07-16
     19      10 2014-12-08
     20      10 2016-04-26
     21      10 2014-05-30

答案 1 :(得分:0)

如果您只需要用测试数据填充空表并且性能很重要,您可以考虑将dml和序列放在一边。为了维持利率,您可以在余数的基础上使用函数ownerId = f(carId)

--drop table owners;
--drop table cars;
--drop table ownership;

create table owners as
  select level n
    from dual
    connect by level < 1000*1000*1;

create table cars as
  select level n
    from dual
    connect by level < 2100*1000*1;

create table ownership as
  select level cid,
         10*trunc(level/21) + case
                                when mod(level, 21) between 0  and  4 then mod(level, 21)
                                when mod(level, 21) between 5  and  6 then 5
                                when mod(level, 21) between 7  and  8 then 6
                                when mod(level, 21) between 9  and 11 then 7
                                when mod(level, 21) between 12 and 15 then 8
                                when mod(level, 21) between 16 and 20 then 9
                              end oid
    from dual
    connect by level < 2100*1000*1;

并检查结果:

with
  cars_by_owner as (
    select oid, count(*) cnt
      from ownership 
      group by oid),
  owners_by_cars_count as (
    select cnt, count(*) c, grouping(cnt) rg
      from cars_by_owner
      group by rollup(cnt))
select f.cnt "cars count",
       f.c "owners count",
       round(f.c/s.c*100) "%"
  from owners_by_cars_count f
  join owners_by_cars_count s
    on f.rg = 0 and s.rg = 1

cars_count  owners_count  %
    1       499999        50
    2       200000        20
    3       100000        10
    4       100000        10
    5       100000        10

创建1M所有者2.1M汽车并填写ownership表需要几秒钟。

如果您遇到ORA-30009,您可能会生成一个带有正数而不是connect by level的辅助表。