Kontinuierlicher Import

Aus FreiBier
Wechseln zu: Navigation, Suche

Beim Import von Daten möchte man manchmal nur geänderte Datensätze einlesen. So kann es zum Beispiel sein, das man die Liste der Produkte bereits aus einem Altsystem importiert hat, dann zur endgültigen Umstellung aber die Daten nochmal synchronisieren will. Nun wäre es schön, wenn man wüsste, welche Daten man bereits importiert hat und welche sich geändert haben. So kann von einem externen Datenbestand von Zeit zu Zeit ein Import gefahren werden und in der Importtabelle kann der Benutzer nur die geänderten Daten sehen und ggf. nochmals von Hand abgleichen.

Grundlage hierzu ist ein Stück SQL-Code, das aus der bestehenden Datenbank eine Tabelle für eine CSV-Datei generiert, wie sie von den ADempiere Import-Prozessen angenommen wird. Dies findet man unten im SQL-Code am Anfang. Es erzeugt die temporäre Tabelle "tmp". Das Prinzip ist nun, das diese Daten nicht direkt ausgegeben werden, sondern zuerst mit einer Tabelle von bereits importierten Datensätzen abgeglichen wird. Vor der endgültigen Ausgabe für den Import merken wir uns dann noch zusätzlich, welche Daten wann importiert wurden.


Ich erzeuge die Tabellen in einem eigenen Schema "importe" innerhalb der Datenbank, die meine importierten Rohdaten enthält, um diese beiden Tabellenarten voneinander abzugrenzen.

 CREATE schema importe;
 
 CREATE TABLE importe.liste_importe(
    id serial NOT NULL, 
    tabelle character varying(15) NOT NULL, 
    "timestamp" timestamp with time zone NOT NULL DEFAULT now()
 );

Nun erzeuge ich den eigentlichen Import mit diesem SQL-Code:

 CREATE TEMPORARY TABLE tmp ON COMMIT DROP AS SELECT 
   'L' || LPAD(TRIM("LiefNum"),3,'0') AS "LieferantenNummer",
   INITCAP(TRIM("LiefBez")) AS "Bezeichnung",
   INITCAP(TRIM("Name1")) AS "Name1",
   INITCAP(TRIM("Name2")) AS "Name2",
   INITCAP(TRIM("Strasse")) AS "Strasse",
   TRIM("Land") AS "Land",
   INITCAP(TRIM("Stadt")) AS "Stadt",
   TRIM("Telefon") AS "Telefon",
   CASE WHEN CAST("LiefNum" AS numeric) IN (
     SELECT "Artikel1"."LieferantenNr"
     FROM "Artikel1" 
     WHERE
       SUBSTRING("Artikel1"."Bezeichnung" FROM 1 FOR 1) NOT IN('*','0',' ')
       AND CHAR_LENGTH("Artikel1"."ArtikelNr") >= 4
       AND CHAR_LENGTH("Artikel1"."Bezeichnung") > 5
       AND "Artikel1"."FaktSperre"='N'
       AND SUBSTRING("DatLetzteBeweg" FROM 1 FOR 2) = '11'
     GROUP BY "Artikel1"."LieferantenNr"
   ) THEN 'Y' ELSE 'N' END AS "aktiv"
 FROM "Liefant1"
 WHERE CAST("LiefNum" AS numeric) BETWEEN 2 AND 999;
 
 -- only the first time:
 --CREATE TABLE importe.lieferanten AS SELECT * FROM tmp WITH NO DATA;
 -- CREATE TABLE importe.lieferanten_log AS SELECT *, CAST(null AS int) AS importnr FROM tmp WITH NO DATA;
 
 CREATE TEMPORARY TABLE changedrecords ON COMMIT DROP AS
   SELECT tmp.*
   FROM tmp INNER JOIN importe.lieferanten USING("LieferantenNummer")
   WHERE ROW(tmp.*) IS DISTINCT FROM ROW(importe.lieferanten.*);
 
 CREATE TEMPORARY TABLE newrecords ON COMMIT DROP AS
   SELECT tmp.*
   FROM tmp LEFT JOIN importe.lieferanten USING("LieferantenNummer")
   WHERE importe.lieferanten."LieferantenNummer" IS NULL;
 
 INSERT INTO importe.lieferanten SELECT * FROM newrecords;
 -- laut http://www.postgresql.org/docs/8.4/static/sql-update.html ("Compatibility")
 -- geht der folgende Update in PostgreSQL (noch) nicht, obwohl er Standard-konform ist.
 -- also mache ich das mit delete und insert
 --UPDATE importe.lieferanten SET(importe.lieferanten.*) = (
 --  SELECT changedrecords.* FROM changedrecords WHERE changedrecords."LieferantenNummer" = importe.lieferanten."LieferantenNummer"
 --);
 DELETE FROM importe.lieferanten WHERE "LieferantenNummer" IN (SELECT "LieferantenNummer" FROM changedrecords);
 INSERT INTO importe.lieferanten SELECT * FROM changedrecords;
 
 insert into importe.liste_importe (tabelle, timestamp) VALUES('lieferanten', now());
 
 insert into importe.lieferanten_log (
   SELECT *, (SELECT MAX(id) FROM importe.liste_importe) AS importnr FROM changedrecords
   UNION
   SELECT *, (SELECT MAX(id) FROM importe.liste_importe) AS importnr FROM newrecords
 );
 
 SELECT * FROM importe.lieferanten_log WHERE importnr=(SELECT MAX(id) FROM importe.liste_importe);
Meine Werkzeuge
Namensräume

Varianten
Aktionen
Navigation
Werkzeuge