externe tabelle load when

DiZan

Benutzer
Beiträge
7
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
 
Werbung:
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.
 
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
 
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?
 
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
 
Code:
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?

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
 
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';
 
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
 
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>
 
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.
 
... 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.
 
Werbung:
Ja, das funktioniert.

Nach dem "CREATE TABLE AS" darf jedes valide SQL SELECT Statement kommen. Und ein WITH ist auch "nur" ein SELECT.
 
Zurück
Oben