import csv/xls auf zwei tabellen (mit schlüssel)?

Hallo,

ich möchte eine csv (excel) Tabelle in zwei DB-Tabelle kopieren (Contact und Company).

Die csv Datei:
Name;Vorname;Company;;

Die DB Tabelle Contact:
Contact_ID; Name; Vorname; Company_ID

Die DB Tabelle Contact:
Company_ID; Company_Name

Die Tabellen sind über Company_ID verbunden.

Ich will das die Spalten Name und Vorname aus der csv Tabelle automatsch in die Contact DB- Tabelle
und die Spalte Company automatsch in die Company DB- Tabelle
kopiert wird und die Zusammengehörigkeit(Contact.Company_ID = Company.Company_ID) gleich mit verbunden wird.

hab leider keine Idee

vielen Dank

Frank

Wie wäre es, die Daten mit einer Scriptsprache deiner Wahl aufzuteilen?

Ansonsten könnten dir ev. noch RULEs weiterhelfen, aber da bin ich mir gerade nicht ganz sicher. Siehe Dokumentation “CREATE RULE”.

Könnten, wenn eine RULE bei COPY wirken würde. Tut sie nicht. Was geht, wäre ein TRIGGER. Ich habe da mal a bissl gespielt, dabei nutze ich eine Hilfstabelle, die den Aufbau der CSV-Datei hat:

Btw.: ich nutze dabei auch Avoid Unique Key violation - ads’ corner g

[php]
test=# create table company (id serial primary key, name text);
NOTICE: CREATE TABLE will create implicit sequence “company_id_seq” for serial column “company.id”
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index “company_pkey” for table “company”
CREATE TABLE
test=# create table contact (id serial primary key, name text, vorname text, company int references company);
NOTICE: CREATE TABLE will create implicit sequence “contact_id_seq” for serial column “contact.id”
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index “contact_pkey” for table “contact”
CREATE TABLE
test=
# commit;
COMMIT
test=# create table contact_import (name text, vorname text, company text);
CREATE TABLE


– Versuch mit RULE

test=# create rule my_import as on insert to contact_import do instead ( insert into company (name) select NEW.company where not exists (select name from company where name=NEW.company); insert into contact (name, vorname, company) select NEW.name, NEW.vorname, id from company where name=NEW.company; );
CREATE RULE
test=
# copy contact_import from stdin;
Enter data to be copied followed by a newline.
End with a backslash and a period on a line by itself.

name1 vorname1 firma1
name2 vorname2 firma2
name11 vorname11 firma1
.
test=*# select * from company;
id | name
----±-----
(0 rows)

test=*# select * from contact;
id | name | vorname | company
----±-----±--------±--------
(0 rows)

test=*# select * from contact_import ;
name | vorname | company
--------±----------±--------
name1 | vorname1 | firma1
name2 | vorname2 | firma2
name11 | vorname11 | firma1
(3 rows)


– die RULE wirkt also nicht bei COPY
– Versuch RULE mit INSERT

test=# rollback;
ROLLBACK
test=# create table contact_import (name text, vorname text, company text);
CREATE TABLE
test=
# create rule my_import as on insert to contact_import do instead ( insert into company (name) select NEW.company where not exists (select name from company where name=NEW.company); insert into contact (name, vorname, company) select NEW.name, NEW.vorname, id from company where name=NEW.company; );
CREATE RULE
test=# insert into contact_import values(‘name1’,‘vorname1’,‘firma1’);
INSERT 0 1
test=
# insert into contact_import values(‘name2’,‘vorname2’,‘firma2’);
INSERT 0 1
test=# insert into contact_import values(‘name11’,‘vorname11’,‘firma1’);
INSERT 0 1
test=
# select * from company;
id | name
----±-------
1 | firma1
2 | firma2
(2 rows)

test=*# select * from contact;
id | name | vorname | company
----±-------±----------±--------
1 | name1 | vorname1 | 1
2 | name2 | vorname2 | 2
3 | name11 | vorname11 | 1
(3 rows)

– schon besser, aber wenn die Daten als CSV vorliegen, ist ein COPY schöner als daraus erst INSERT zu frickeln.
– was also tun?
– Versuch mit TRIGGER, nicht ausformuliert, nur ein Test, ob der Trigger bei COPY feuert:

test=# create table contact_import (name text, vorname text, company text);
CREATE TABLE
test=# create function my_copy() returns trigger as $$begin raise notice ‘test’;return NEW; end;$$ language plpgsql;
CREATE FUNCTION
test=
# create trigger m_tg before insert on contact_import for each row execute procedure my_copy();
CREATE TRIGGER
test=*# copy contact_import from stdin;
Enter data to be copied followed by a newline.
End with a backslash and a period on a line by itself.

a1 b1 c1
a2 b2 c2
a11 b11 c1
.
NOTICE: test
CONTEXT: COPY contact_import, line 1: “a1 b1 c1”
NOTICE: test
CONTEXT: COPY contact_import, line 2: “a2 b2 c2”
NOTICE: test
CONTEXT: COPY contact_import, line 3: “a11 b11 c1”
test=*#

[/php]

Der TRIGGER feuert also beim COPY. Man braucht nun also nur noch die Triggerfunktion sinnvoll zu schreiben. Das überlasse ich mal dem Fragesteller zur Übung. Er könnte auch die RULE nutzen, dazu einfach nur 2 gleich aufgebaute Hilfstabellen: in die eine erst mit COPY die Daten reintun, dann via INSERT die Daten in die zweite werfen. Auf dieser liegt dann die RULE.


So, nun aber erst mal einen Kaffee…

Andreas

ui!!

Ich hab gestern schon angefangen selber ein Skript zu entwerfen, aber das ist ja super!!

Mir fehlt zwar noch etwas Verständnis dafür, weil ich gerade erst mit dem SQL Gedöns angefangen hab, aber das werd ich dank deiner Hilfe übernehmen.

Wie komme ich dan an so eine sql Konsole ran? (ich nehm an das ist solch eine auf der du das geschrieben hast)

greez
Frank

psql

Andreas

habs gefunden!!!

ich nochmals,

habe die funktion geändert und bekomme eine meldung:

control reached end of trigger without return

was hab ich falsch gemacht

CREATE OR REPLACE FUNCTION my_copy2()
  RETURNS "trigger" AS
'begin insert into company (name) select NEW.company where not exists (select name from company where name=NEW.company); insert into contact (name, vorname, company) select NEW.name, NEW.vorname, id from company where name=NEW.company;  end;'
  LANGUAGE 'plpgsql' VOLATILE;
ALTER FUNCTION my_copy2() OWNER TO postgres;

danke

Ist das nicht eindeutig?

nö,

mir zumindest nicht

Deine Funktion muss ein RETURN enthalten.
Da du eine TRIGGER Funktion definierst, musst du auch einen Wert vom Typ TRIGGER zurückgeben.

Hier bieten sich NEW oder OLD an …

RETURNS “trigger” AS

tu ich das denn nicht damit,

sorry, bin anfänger.

Frank

Die Feinheiten der englischen Sprache :wink:

Mit RETURNS sagst du bloss, was die Funktion zurückliefern soll.
Aber in deiner Funktion selbst musst du noch mindestens eine Stelle haben, die auch wirklich etwas zurückliefert. Das macht dann RETURN.

es funzt, viele Dank

CREATE OR REPLACE FUNCTION my_copy2()
  RETURNS "trigger" AS
$BODY$begin
insert into company (name) select NEW.company where not exists (select name from company where name=NEW.company); 
insert into contact (name, vorname, company) select NEW.name, NEW.vorname, id from company where name=NEW.company;
return NEW;
end;$BODY$
  LANGUAGE 'plpgsql' VOLATILE;
ALTER FUNCTION my_copy2() OWNER TO postgres;

War zu erwarten g

Viel Spass damit.

das funktioniert super,

nur ein kleine Problem hab ich noch:

die ä ö ü’s können irgentwie nicht richtig verarbeitet werden.

Wenn ich das select im terminal aufrufe, kann ich die Umlaute sehen.
Wenn ich die Daten Im PgAdminIII ansehe, sind nur noch kästen zu sehen.
genau wie in meinem Datagrid.

Wenn ich direkt im Datagrid Daten (äöü) eingebe, können diese zwar im Datagrid angezeigt werden, aber im PGAdminIII sieht man nur Zeichenfolgen.
was kann das sein?

danke!!

unterschiedliche Einstellungen für client_encoding.

Andreas

Die Lösung findest Du unter PgAdmin Fehlermeldungen.

PostgreSQL: Documentation: Manuals: PostgreSQL 8.2: Character Set Support

mfg

fristo

Hallo,

ich hab erneut ein Problem

ich habe die contact_import tabelle mal gelöscht und wollte einzelne Datensätze löschen (Datagrid.update).
bei denen die ich mit Hand eingepflegt hatte funktioniert das.
Bei den importierten lassen sich die Einträge nicht mehr löschen

: Der UpdateCommand hat sich auf 0 der erwarteten 1 Datensätze ausgewirkt.<<
wie kommt das?

vielen Dank
Gruss
Frank