txt2sql - gibt"s das?
am 20.07.2006 16:31:58 von unknownPost removed (X-No-Archive: yes)
Post removed (X-No-Archive: yes)
Martin Trautmann schrieb:
> Hallo,
>
> kennt jemand kleine Helferlein, die ueber ein Text-Austauschformat eine
> passende SQL-Syntax erzeugen koennen?
>
> Beispiel: Austauschformat ist semikolon-getrennter Text (.csv).
>
> Aus groesseren Datenmengen wird ein diff erstellt:
>
>
> alt.csv:
> id;field1;field2
> 1;A1;A2
> 2;B1;B2
>
> neu.csv:
> id;field1;field2
> 1;A1;A3
> 2;B1;
>
> diff.csv:
> id;field1;field2
> 1;;-A2/A3
> 2;;-B2
>
> Typischer sind in der Regel Erweiterungen, wo bisher nichts steht. Aber
> die Loeschung von Daten habe ich hier einmal mit vorangestelltem "-"
> markiert. Aus dem diff.csv sollte dann folgendes erzeugt werden:
>
> diff.sql:
> /* table xyz: id, text, from, until */
> INSERT INTO xyz VALUES(1,'A2',null,'2006-07-20')
> INSERT INTO xyz VALUES(1,'A3','2006-07-20',null)
> INSERT INTO xyz VALUES(1,'B2',null,'2006-07-20')
>
> Ich wollte mir hier ein paar Perl-scripts dazu erstellen. Aber
> vielleicht hat das schon jemand erledigt - und vermutlich besser als ich
> es schaffen wuerde ;-)
Du könntest mit DBD::CSV die Daten aus den CSV-Dateien lesen und mit
DBD::MySQL in die Datenbank schreiben. Allerdings scheint mir Dein
Beispiel nicht ganz klar zu sein. Wenn ich die textuelle Erklärung
richtig verstehe, dann sollte ja an A2 aus der Tabelle verschwinden -
Du schreibst es hier aber in die Tabelle rein. Wann Du NULL und wann
Du ein Datum haben willst, weiß außer Dir auch niemand ...
Post removed (X-No-Archive: yes)
Martin Trautmann schrieb:
> On Thu, 20 Jul 2006 16:36:30 +0200, Christian Kirsch wrote:
>>> alt.csv:
>>> id;field1;field2
>>> 1;A1;A2
>>> 2;B1;B2
>>>
>>> neu.csv:
>>> id;field1;field2
>>> 1;A1;A3
>>> 2;B1;
>
>>> diff.sql:
>>> /* table xyz: id, text, from, until */
>>> INSERT INTO xyz VALUES(1,'A2',null,'2006-07-20')
>>> INSERT INTO xyz VALUES(1,'A3','2006-07-20',null)
>>> INSERT INTO xyz VALUES(1,'B2',null,'2006-07-20')
>
>> Du könntest mit DBD::CSV die Daten aus den CSV-Dateien lesen und mit
>> DBD::MySQL in die Datenbank schreiben. Allerdings scheint mir Dein
>> Beispiel nicht ganz klar zu sein. Wenn ich die textuelle Erklärung
>> richtig verstehe, dann sollte ja an A2 aus der Tabelle verschwinden -
>> Du schreibst es hier aber in die Tabelle rein. Wann Du NULL und wann
>> Du ein Datum haben willst, weiß außer Dir auch niemand ...
>
> Das Beispiel sollte einfach zeigen, dass der Wert von A2 auf A3
> geaendert wurde.
>
Dafür würde ich UPDATE nehmen. Das da oben fügt einfach zwei Werte in
die Tabelle ein (nämlich die Zeilen für A2 und A3).
> Die eine Moeglichkeit waere nun, A2 einfach aus der Tabelle zu loeschen.
> Die andere ist, den alten Wert als ungueltig zu markieren - als
> vereinfachter Ansatz zum Versionsmanagement, mit dem man Aenderungen
> auch wieder rueckgaengig machen koennte.
Mit INSERT markierst Du auch nichts als ungültig - Du trägst einfach
nur einen neuen Wert ein.
>
> Ich wollte an der Stelle nicht unendlich in die Details der Umsetzung
> einsteigen - aber vielleicht hat da auch schon jemand den noetigen
> Erfahrungs-Vorsprung und Tool-Kenntnisse. Daher als Erklaerung:
>
Naja, wenn die SQL-Kommandos korrekt wären, könnte man auch verstehen,
was Du erreichen willst.
> 'A2' kann entweder falsch sein und wurde durch 'A3' korrigiert.
.... oder?
> Es kann aber auch sein, dass 'A2' bis zu einem bestimmten Datum gueltig
> war, und dann 'A3' gueltig wurde. Welches von beidem der Fall ist, das
> hatte ich hier nicht erlaeutert. Solche Information kann beispielsweise
> implizit geboten sein:
>
> A2 steht fuer Einwohner, Guthaben, Umtauschkurs oder sonstiges:
> A2 = 3.0 (2004-01-01)
> A3 = 3.25 (2006-03-01)
>
> Das Datum von A2 und A3 kann im Wert selbst versteckt sein, es kann sich
> aus dem Dateinamen ergeben (z.B. neu.csv = 2006-03-01), es kann irgendwo
> in der Datei vermerkt sein usw.
>
Du möchtest offensichtlich ein DWIM-Werkzeug (Do What I Mean). Sowas
schreibt man sich am besten selbst. Ich bezweifle jedenfalls, dass
außer Dir jemand Deine Anforderungen versteht. Die Anforderungen an
die Daten sind so allgemein, dass sie praktisch abwesend sind. Wie
willst Du sowas mit einem allgemeinen Programm erschlagen?
> Im konkreten Beispiel habe ich all das vernachlaessigt und als default
> das heutige Datum angesetzt:
>
> A2 war der bis heute gueltige Wert. Nun wird er als ungueltig markiert,
> indem 'until' auf's heutige Datum gesetzt wird. Unter der Annahme, dass
> der alte Anfangswert schon gegeben ist, muesste ich insgesamt zuerst
> pruefen:
> field2 von id '1' hat 'until' null (war also bisher gueltig)
> field2 von id '1' hat ein 'from' mit 2004-01-01
>
> -> INSERT INTO xyz VALUES(1,'A2','2004-01-01','2006-07-20')
>
Das ändert ja am Bierpreis nix: Du fügst einfach nur einen neuen
Eintrag ein, änderst aber gar nix an dem vorhandenen. Wenn ID ein
Primary Key oder ein Unique Index ist, gibt's dann immerhin noch
kostenlos eine Fehlermeldung von MySQL...
>
> Wird's mit diesen Infos klarer?
>
Nur unwesentlich.
>
> Mein Verdacht ist, dass ich vermutlich mit unmittelbaren Arbeiten
> innerhalb von SQL besser fahren koennte: eine Datenbank nimmt alt.csv
> auf, eine Datenbank nimmt neu.csv auf, und die Differenz wird innerhalb
> von SQL ermittelt.
>
Mein Verdacht ist, dass Du bislang nicht richtig erklärt hast,
- woher die Daten kommen
- wohin sie sollen
- warum Du überhaupt sowas wie DIFF machen willst (statt direkt UPDATE
und Freunde).
> Ich dachte eher an Vorarbeiten auf der reinen Text-Ebene,
>
> * weil .csv ein universelles Austauschformat darstellt, das ohne SQL
> nutzbar ist
>
.... stimmt. Das kann man mit praktisch jeder Tabellenkalkulation
nutzen. Ob das jetzt ein Vorteil gegenüber SQL ist?
> * weil alt.csv nicht unbedingt zur Verfuegung steht: Gegeben wird
> vor allem das diff.csv, das als update bereitsteht.
Und ein DIFF kommt jetzt woher, wenn nicht durch den Vergleich von alt
und neu? Teilchenfluss aus einem Paralleluniversum?
> Es geht um's
> Einpflegen der Korrekturen einer Teilmenge aus den komkreten
> diff
Entschuldige, aber mir kommt es so vor, als ob Du mit diesem Projekt
bei http://thedailywtf.com/ landen könntest - falls es jemals fertig
wird ;-)
>
> * weil diff.csv nur einen Teilbereich abdecken muss:
> Uebertragen werden z.B. nur die IDs, wo tatsaechlich Aenderungen
> stattfanden. Uebertragen werden auch nur die 'Spalten', die
> fuer die Problematik als update erforderlich sind
Und um diese vermeintlichen Vorteile nutzen zu können, darfst Du dann
anschließend komplexe Perl/Python/Ruby-Skripts schreiben, die die
Spar-Notation auspacken und wieder in irgendetwas sinnvolles umsetzen.
Post removed (X-No-Archive: yes)
Martin Trautmann schrieb:
> On Thu, 20 Jul 2006 17:35:19 +0200, Christian Kirsch wrote:
>>> Das Beispiel sollte einfach zeigen, dass der Wert von A2 auf A3
>>> geaendert wurde.
>>>
>> Dafür würde ich UPDATE nehmen. Das da oben fügt einfach zwei Werte in
>> die Tabelle ein (nämlich die Zeilen für A2 und A3).
>
> Ok, von mir aus sehr gerne auch ein UPDATE fuer A2 (weil das 'until' ja
> ueberschrieben wuerde). Aber auch ein UPDATE fuer A3? Gehe ich hier
> faelschlicherweise davon aus, dass mir das A3 dann nur das A2
> ueberschreiben wuerde? Das A2 soll nicht verlorengehen.
>
Wenn ich es jetzt richtig verstehe, dann willst Du für bestimmte
Datensätze eine "Geschichte" haben: Welche Werte galten wann. Wenn's den
Wert noch nicht gibt, trägst Du ihn mit "INSERT" ein, setzt das
"since"-Feld auf now() und das "until"-Feld auf NULL. Gibt's den Wert
und er soll nicht mehr gültig sein, setzt Du until auf now(). So weit,
so gut?
> Richtig - der alte bleibt noch verfuegbar. Dass bei der Abfrage nur A3,
> nicht aber A2 angezeigt wird, ist durch die Art der Abfrage entsprechend
> zu gewaehrleisten.
>
Darf man sich das so vorstellen, dass A2/A3 vielleicht Mieten oder
Wechselkurse sind?
>> Ich bezweifle jedenfalls, dass
>> außer Dir jemand Deine Anforderungen versteht. Die Anforderungen an
>> die Daten sind so allgemein, dass sie praktisch abwesend sind. Wie
>> willst Du sowas mit einem allgemeinen Programm erschlagen?
>
> Naja - die Anforderungen klingen auf mich recht ueblich:
> Nimm eine Update-Datei und verwurtse ihre Inhalte mit dem bisherigen
> Stand so, dass die Korrekturen dokumentiert und reversibel sind.
>
Für "sowas" nimmt man CVS bzw. heutzutage Subversion. Das macht dann den
Diff-Kram selber ... Ich finde es etwas merkwürdig, erst aus zwei
verschiedenen Datensätzen eine "Differenz" zu berechnen, um dann aus der
wieder einzelne Datensätze zu machen. Kann man tun - aber kann man seine
Zeit nicht anders totschlagen?
>
>>> A2 war der bis heute gueltige Wert. Nun wird er als ungueltig markiert,
zumindest wird seine Gültigkeit auf "heute" begrenzt.
>>> indem 'until' auf's heutige Datum gesetzt wird. Unter der Annahme, dass
>>> der alte Anfangswert schon gegeben ist, muesste ich insgesamt zuerst
>>> pruefen:
>>> field2 von id '1' hat 'until' null (war also bisher gueltig)
>>> field2 von id '1' hat ein 'from' mit 2004-01-01
>>>
>>> -> INSERT INTO xyz VALUES(1,'A2','2004-01-01','2006-07-20')
>>>
>> Das ändert ja am Bierpreis nix: Du fügst einfach nur einen neuen
>> Eintrag ein, änderst aber gar nix an dem vorhandenen. Wenn ID ein
>> Primary Key oder ein Unique Index ist, gibt's dann immerhin noch
>> kostenlos eine Fehlermeldung von MySQL...
>
> Fuege von mir aus statt des INSERT zuvor ein DELETE ein, verwende statt
aber dann ist doch gerade die Geschichte weg?
> dessen ein UPDATE usw. - das halte ich fuer zweitrangige Probleme, die
> dann recht einfach zu ergaenzen sind. Fuer mich stellt das Hauptproblem
> insgesamt die Erzeugung eines grob passenden SQLs dar.
> UPDATE/DELETE/INSERT sind fuer mich die geringeren Unterschiede.
>
Nach Deiner Beschreibung war bislang ja noch nicht mal klar, was "ein
grob passendes SQL" überhaupt sein *könnte*.
> ID in xyz darf uebrigens natuerlich beliebige Duplikate haben - es gibt
Das ist nicht meine Vorstellung von "ID" und "natürlich".
> ja noch immer xy1 mit eindeutigen IDs, das sich aus xyz dann das
> passende (z.B. das mit dem gueltigsten Datum) heraussucht.
Hä?
>
>> Mein Verdacht ist, dass Du bislang nicht richtig erklärt hast,
>> - woher die Daten kommen
>
> Irgendwer stellt nach bestem Ermessen eine Update-Datei zur Verfuegung.
Warum nur, warum? Kann er nicht einfach die aktuellen DATEN zur
Verfügung stellen? Denn *die* willst Du doch haben (ebenso wie die
alten). Oder?
> Kleinster gemeinsamer Nenner: Es gibt eine eindeutige ID, und es ist
> klar, wohin der Wert kommen soll.
>
Wie jetzt - gerade war die ID doch noch nicht eindeutig.
>> - wohin sie sollen
>
> In die SQL-Datenbank 'ich-hab-alt-wenigeralt-und-krieg-jetzt-neu'
>
Nö. Du hast alt und bekommst "Diff". Und daraus willst Du jetzt "neu"
machen, obwohl doch jemand anders schon das "neu" hatte und daraus
"Diff" gemacht hat.
>> - warum Du überhaupt sowas wie DIFF machen willst (statt direkt UPDATE
>> und Freunde).
>
> Weil die Quelle ganz ohne SQL arbeitet
>
>>> * weil .csv ein universelles Austauschformat darstellt, das ohne SQL
>>> nutzbar ist
>>>
>> ... stimmt. Das kann man mit praktisch jeder Tabellenkalkulation
>> nutzen. Ob das jetzt ein Vorteil gegenüber SQL ist?
>
> Es gibt auch ein Leben ausserhalb von SQL, wo sowas ein Vorteil sein
> mag.
>
Mag ja sein - aber dann nimm doch das aktuelle CSV und arbeite damit.
>>> * weil alt.csv nicht unbedingt zur Verfuegung steht: Gegeben wird
>>> vor allem das diff.csv, das als update bereitsteht.
>> Und ein DIFF kommt jetzt woher, wenn nicht durch den Vergleich von alt
>> und neu? Teilchenfluss aus einem Paralleluniversum?
>
> Ja, genau. Irgendwer kennt alt.txt (zumindest in Teilen) und sagt: Ei,
> manno, ist doch schnee von gestern, ich gebe dir neu.txt
>
Hä?
> Naja - dann erklaer's ich halt am konkreten Beispiel. Du kennst
> opengeodb? Dort gibt's kilozig freie Geokoordinaten - also nicht
> wirklich viel, aber genug, um manuelles Einpflegen zur Qual zu machen.
>
Geokoordinaten wären jetzt nicht unbedingt die Daten, die mir spontan
als "ändern sich häufig, da brauche ich eine Geschichte von" einfallen
würden.
> Nun kommt also jemand daher und sagt: Moment, in MeckPomm sind schon
> wieder 20 Gemeinden aufgeloest worden:
>
> id, war Gemeindenr, gehoert nun zur Gemeinde
> 22334, 12345678, 12345666
> 22335, 12345679, 12345666
> 22355, 12345777, 12345700
> usw.
>
M.W passiert sowas in einer Gebietsreform. Die vielleicht alle 20 Jahre
mal stattfindet. Wenn überhaupt.
> Oder ein anderer sagt: Hoppla, euch fehlen noch die letzten 100 neuen
> Postleitzahlen:
> id PLZ
> 12345 04711
> ...
>
Das sind dann ja neue Daten - da reicht doch ein INSERT.
> Ein anderer meint: Also nee, wie ihr die Orte in Osttirol zugeordnet
> habt, das ist voellig falsch:
> id, richtige Koordinaten
> 334455+50.60+10.20
>
> id, gehoert zu Bezirk
> 334455
>
Das sind korrekte Daten. Wozu willst Du die flaschen aufheben? Da tuts
ein UPDATE bla set Bezirk=fasel where id=weißnich
> usw.
>
> Einer schickt die neusten Einwohnerzahlen aus Bielefeld...
>
> Auf der Mailing list wird dann diskutiert
> id | name | richtiger Name
> 12345 | Bielefeld-West | Vorder-Bielefeld
>
> usw. You get the idea? .csv ist einfach ein universelles Format, das aus
> fast jeder Quelle rauspurzeln kann. Dies aber in SQL reinzukriegen, das
> soll weitmoeglichst vereinfacht werden.
>
Mit CSV odder so hat das recht wenig zu tun - Du könntest auch XML
sagen, letztlich ist es wurscht. Eigentlich musst Du bei jedem Problem
nur entscheiden, ob Du vorhandene Daten überschreiben ('Koordinaten
stimmen nicht') willst oder den historischen Verlauf brauchst. Ein
allgemeines Script zu schreiben dürfte länger dauern als kleine,
einzelne, die Das Richtige (tm) tun.
Dein Konzept riecht nach Over-Engineering: Sollte es jemals fertig
werden, wäre es bestimmt total klasse. Aber es wird vermutlich nicht fertig.
Post removed (X-No-Archive: yes)
Martin Trautmann wrote:
> Daran erkennt man schon eines der Probleme: ein diff von alt.txt nach
> neu.txt enthaelt nur die Aenderungen, die zwische alt und neu sich
> vorwaerts entwickelten. Trifft nun alt auf wenigeralt, so werden
> moeglicherweise diese Aenderungen wieder zurueckgedreht - das muss
> natuerlich verhindert werden.
Du kennst zu jeder Datei den "Wirkungszeitpunkt", hast die Dateien aber
prinzipiell einzeln? Dann würde ich es bspw. mit einer temporären
Tabelle lösen:
CSV auf welchem Wege auch immer in die temporäre Tabelle temp laden,
Variable @date auf das Datum der Datei setzen (falls "wenigeralt" nach
"neu" eingepflegt werden soll).
daten sei die permanente Datentabelle.
Dann ein
UPDATE daten JOIN temp ON was auch immer SET bis=@date WHERE ID=... AND
Datenwert weicht ab
INSERT INTO daten (ID, wert, von, bis) SELECT ID, wert, @date, NULL from
temp WHERE ...
So was in der Richtung halt, also eben auf SQL-Ebene statt mit dem diff
herumzuhantieren.
Thomas
--
Kaum macht man's richtig, schon geht's.
Post removed (X-No-Archive: yes)