1. Willkommen im Forum für alle Datenbanken! Registriere Dich kostenlos und diskutiere über DBs wie Mysql, MariaDB, Oracle, Sql-Server, Postgres, Access uvm
    Information ausblenden

externe tabelle load when

Dieses Thema im Forum "Oracle" wurde erstellt von DiZan, 22 Januar 2020.

  1. DiZan

    DiZan Benutzer

    ich möchte eine Textdatei in eine externe Tabelle laden. Das besondere dabei ist, dass die Daten, die importiert werden sollen, sich auf mehrere Zeilen verteilen:

    Beispiel:
    SEGMENT;FELD1,FELD2;FELD3;FELD4;FELD5
    BP01;12345678;Meier;Rudolf;Hutmacher;
    ADDR;Bahnhofsstr.;23;44319;Dortmund;
    BP01;12345679;Müller;Heinz;Hundetrainer;
    ADDR;Waldstr;12;58239;Schwerte;

    Die Zeile BP01 und ADDR, die hier untereinander stehen, sollen aber in eine Zeile geladen werden, so dass das Ganze hinterher in der Tabelle wie folgt aussieht:

    BP01;12345678;Meier;Rudolf;Hutmacher;ADDR;Bahnhofsstr.;23;44319;Dortmund;
    BP01;12345679;Müller;Heinz;Hundetrainer;ADDR;Waldstr;12;58239;Schwerte;

    Eine Zeile in eine externe Tabelle laden kann ich, die CTL-Datei hab ich ebenfalls, aber leider hat man die Importdatei umgebaut, so dass sie jetzt so aussieht, wie hier beschrieben.
    Ich steh hier leider total auf dem Schlauch.

    Kann man das direkt im Ladevorgang der externen Tabelle machen und wie? Oder gibt es vielleicht einen anderen Weg in Form einer Nachbearbeitung?

    viele Grüße
    DiZan
     
  2. castorp

    castorp Datenbank-Guru

    Soweit ich weiß unterstützt der SQL*Loader (und das ist es, was "External Tables" verwenden) keine Datensätze die über mehr als eine Zeile gehen.

    Ich denke die einzige Chance die Du hast, ist die Datei via sed oder anderen Tools so umzustellen, dass jeder Datensatz wieder in einer Zeile steht.
     
  3. DiZan

    DiZan Benutzer

    Danke für die schnelle Antwort.
    Wenn ich das Flatfile dann einfach so wie es ist, in eine Tabelle lade, also sagen wir mal Tabellenname: adress_stage dann hab ich es schon mal in der Datenbank

    Beispiel:
    SEGMENT;FELD1,FELD2;FELD3;FELD4;FELD5
    BP01;12345678;Meier;Rudolf;Hutmacher;
    ADDR;Bahnhofsstr.;23;44319;Dortmund;
    BP01;12345679;Müller;Heinz;Hundetrainer;
    ADDR;Waldstr;12;58239;Schwerte;
    (...)

    kennt dann jemand eine Möglichkeit, die Zeilen dann aus der stage-Tabelle in eine neue Tabelle, sagen wird mal: adress, so zu übernehmen, dass sie dann der neuen Tabelle "adress" nebeneinander stehen

    BP01;12345678;Meier;Rudolf;Hutmacher;ADDR;Bahnhofsstr.;23;44319;Dortmund;
    BP01;12345679;Müller;Heinz;Hundetrainer;ADDR;Waldstr;12;58239;Schwerte;

    Mit einfachem SQL komm ich einigermaßen zurecht, es meinte mal jemand, das müsste man ggfs. mit einer PL/SQL Prozedur machen, da habe ich nur keine Idee, wie so was geht...

    viele Grüße
    Dirk
     
  4. akretschmer

    akretschmer Datenbank-Guru

    Code:
    test=*# select * from dizan ;
     segment |    feld1     | feld2  | feld3  |    feld4     | feld5
    ---------+--------------+--------+--------+--------------+-------
     BP01    | 12345678     | Meier  | Rudolf | Hutmacher    |
     ADDR    | Bahnhofsstr. | 23     | 44319  | Dortmund     |
     BP01    | 12345679     | Müller | Heinz  | Hundetrainer |
     ADDR    | Waldstr      | 12     | 58239  | Schwerte     |
    (4 rows)
    
    test=*# with tmp as (select row_number() over (), * from dizan ) select t1.*, t2.* from tmp t1 left join tmp t2 on t2.row_number = t1.row_number+1 and t1.segment='BP01' and t2.segment='ADDR' where t1.segment='BP01';
     row_number | segment |  feld1   | feld2  | feld3  |    feld4     | feld5 | row_number | segment |    feld1     | feld2 | feld3 |  feld4   | feld5
    ------------+---------+----------+--------+--------+--------------+-------+------------+---------+--------------+-------+-------+----------+-------
              1 | BP01    | 12345678 | Meier  | Rudolf | Hutmacher    |       |          2 | ADDR    | Bahnhofsstr. | 23    | 44319 | Dortmund |
              3 | BP01    | 12345679 | Müller | Heinz  | Hundetrainer |       |          4 | ADDR    | Waldstr      | 12    | 58239 | Schwerte |
    (2 rows)
    
    test=*#
    
    vielleicht so?
     
    DiZan gefällt das.
  5. DiZan

    DiZan Benutzer

    Hallo akretschmer,
    sorry, ich war gestern den ganzen Tag unterwegs. Vielen Dank für Deine Hilfe.
    So ein tmp-Konstrukt kannte ich noch gar nicht, werde ich sofort mal auf meiner Datenbank ausprobieren.

    viele Grüße
    Dirk
     
  6. DiZan

    DiZan Benutzer

    mh. ich weiß nicht warum, aber es kommt eine Fehlermeldung.
    Code:
    ORA-30485: ORDER BY-Ausdruck fehlt in Fensterspezifikation
    30485. 00000 -  "missing ORDER BY expression in the window specification"
    *Cause:    Either the ORDER BY expression is mandatory for this function, or
               there is an aggregation group without any ORDER by expression.
    *Action:
    
    Fehler in Zeile: 1 Spalte: 21
    
    
    Da ich dieses Tmp-Konstrukt bisher nicht kannte, kann ich mir leider auch nicht erklären, warum hier ein "group by" rein interpretiert wird...

    viele Grüße
    Dirk
     
  7. castorp

    castorp Datenbank-Guru

    Du kannst in Oracle einfach ein dummy order by verwenden und Du musst der Spalte einen Alias geben sonst generiert Oracle einen sehr merkwürdigen Namen. Ausserdem muss das * mit einem Tabellen-Alias verwendet werden
    Code:
    with tmp as (
      select row_number() over (order by 1) as rn, d.*
      from dizan
    )
    select t1.*, t2.*
    from tmp t1
      left join tmp t2 on t2.rn = t1.rn + 1 and t2.segment='ADDR'
    where t1.segment='BP01';
    
     
    DiZan und Walter gefällt das.
  8. DiZan

    DiZan Benutzer

    Ganz herzlichen Dank, lieber Castorp. Das funktioniert jetzt wunderbar.:)
     
  9. DiZan

    DiZan Benutzer

    Hallo nochmal,

    gibt es auch eine Möglichkeit das Ergebnis da oben in eine andere Tabelle einzufügen?
    Vielleicht in dem man die Abfrage da oben gleich in ein "create table" einbaut oder per "insert" in einen neue, leere Tabelle einfügt?
    Ich hab's jetzt eine längere Zeitlang versucht, klappt aber nicht...

    viele Grüße
    Dirk
     
  10. akretschmer

    akretschmer Datenbank-Guru

    Code:
    create table ... as select * from ...
    
     
  11. DiZan

    DiZan Benutzer

    ja, das hatte ich auch so gedacht, klappt aber nicht...

    <code>
    Fehler beim Start in Zeile: 1 in Befehl -

    create table NEUT as
    (select * from
    with tmp as
    (select row_number() over (order by 1) as rn, d.*
    from "test" d
    )
    select t1.*, t2.*
    from tmp t1
    left join tmp t2 on t2.rn = t1.rn + 1 and t2.segment='ADDR'
    where t1.segment='BP01')

    Fehlerbericht -
    ORA-00903: Ungültiger Tabellenname
    00903. 00000 - "invalid table name"
    *Cause:
    *Action:

    </code>
     
  12. castorp

    castorp Datenbank-Guru

    Das äussere SELECT ist überflüssig:
    Code:
    create table NEUT
    as
    with tmp as (
      select row_number() over (order by 1) as rn, d.*
      from "test" d
    )
    select t1.*, t2.*
    from tmp t1
      left join tmp t2 on t2.rn = t1.rn + 1 and t2.segment='ADDR'
    where t1.segment='BP01';
    Das wird aber einen weiteren Fehler generieren, da t1.*, t2.* doppelte Spaltennamen generiert, und in einer Tabelle muss jeder Spaltenname nur einmal vorkommen (anders als bei einem SELECT).
    Statt select t1.*, t2.* musst Du die Spalten explizit auflisten.
     
    Walter und akretschmer gefällt das.
  13. akretschmer

    akretschmer Datenbank-Guru

    ... wobei ich mir nicht ganz sicher bin, ob Ora das Resultat einer WITH-Abfrage für nachfolgende schreibende Operationen nutzen kann. Wäre nett, wenn @DiZan das dann bestätigen könnte, ob das klappt.
     
  14. castorp

    castorp Datenbank-Guru

    Ja, das funktioniert.

    Nach dem "CREATE TABLE AS" darf jedes valide SQL SELECT Statement kommen. Und ein WITH ist auch "nur" ein SELECT.
     
Die Seite wird geladen...

Diese Seite empfehlen

  1. Diese Seite verwendet Cookies. Wenn du dich weiterhin auf dieser Seite aufhältst, akzeptierst du unseren Einsatz von Cookies.
    Information ausblenden