2016-08-16 2 views
1

Ich habe viel gesucht und konnte meine Frage noch nicht beantworten.

Also, ich muss eine Menge Daten (Millionen von Zeilen) in verschiedenen Tabellen erzeugen, und dieses Skript sollte schnell sein. Lassen Sie uns nun über drei spezifische Tabellen sprechen, in diese ID Reihen gibt es:SQL, ORACLE: Aktualisiere den Wert einer Spalte mit verschiedenen Werten

  • in Tabelle Owners die ID beginnt von 10000, um 1 erhöht (mit Sequenz)
  • in Tabelle Autos die ID beginnt bei 10000000, erhöht um 1 (mit Sequenz).


In der dritten Tabelle, genannt Eigentum, muss ich diese IDs mit einigen spezifischen Raten "merge":

  • 50% der Besitzer haben 1 Auto
  • 20% die übrigen Eigentümer haben 2 Autos
  • 10-10-10% des Restes wird 3 haben, 4 und 5 Autos


Wichtige Dinge:

  • Hinweis für Owners und Autos Tabellen: Die Preise: 100 Einheit Eigentümer, werden 210 Einheit Autos erzeugt werden, und in der Eigentümer Tabelle werden die Autos eindeutig sein, so 210 Zeilen werden in dieser Tabelle werden auch
  • zuerst die Owners, dann sind die Autos Zeilen werden
  • dann erzeugt werden ich in sert in die Eigentümer Tabelle einige Werte "von" Autos



Hinweise: Hier ist, wie ich Zeilen erzeugt in Autos (Owners ähnlich ist)
(Es wird v_custom_unit Stücke erzeugen Zeilen, diese Einheit wird aus den Raten berechnet, die ich vor ein paar Zeilen geben (für 100 Besitzer Einheit 210 Einheiten Autos generiert werden und 210 Einheiten Eigentum), und dann habe ich eine for-Schleife verwendet, um die Zeilen zu multiplizieren):

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; 

Multiplying ist wie folgt:

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; 

Der nächste Schritt ist Eigentümer Zeilen zu generieren:

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

kommt mein Problem: Jedes Auto ist im Eigentum mit ownerId = 1.
Meine Frage ist: Wie kann ich die Ownership Tabelle mit verschiedenen Besitzerwerten in einem einzigen Update aktualisieren (und vielleicht die Raten (50% -20% -10% -10% -10%) beibehalten)?

Antwort

0

Eine der Möglichkeiten, es zu tun:

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 

Dies ist eine Demo für 10 Besitzer und 21 Autos. Ich bin mir nicht sicher über die Effizienz, aber das ist nur eine rekursive Abfrage. Oracle 11g benötigt.

Testtabelle und Ausgang:

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 
+0

Vielen Dank für Ihre Antwort! Leider habe ich eine neue Information erhalten, nachdem ich die Frage gestellt habe, die die Datengenerierung einfacher gemacht hat, aber ich werde das als Antwort akzeptieren, weil es nützlich ist und ich hätte mit den Zahlen in der Abfrage arbeiten müssen, um mehr Zeilen zu generieren. Bald werde ich meine Lösung teilen, wenn Sie (und jeder andere) daran interessiert ist. – Pohkalopokh

0

Wenn alles, was Sie brauchen, ist leer Tabellen mit Testdaten und Leistung zu füllen ist wichtig, können Sie prüfen beiseite DML und Sequenzen zu verlassen. Um die Raten zu erhalten, können Sie die Funktion ownerId = f(carId) auf der Basis von Resten verwenden.

--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; 

Und Prüfergebnis:

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 

Es dauert einige Sekunden, 1 M Besitzer 2.1M Autos zu erstellen und ownership Tabelle füllen.

Wenn Sie auf ORA-30009 stoßen, können Sie eine Hilfstabelle mit positiven Zahlen erstellen, anstatt connect by level zu verwenden.

Verwandte Themen