Datenimport in PostgreSQL datenbank mit Hilfe von Phyton

Code-Stücke können hier veröffentlicht werden.
BoOnOdY
User
Beiträge: 112
Registriert: Samstag 22. Juli 2006, 13:38

Hey vielen Dank noch ma,

jetzt hab ich nur noch ein kleines Problem,
wie setzt sich die Uhrzeit funktion zusammen?
Man kann zwar aus meiner csv die uhrzeit mit milisekunden auslesen, ich will diese letzte Stelle aber nicht in meiner SQL tabelle haben.

danke schon ma :)

glg tim
BoOnOdY
User
Beiträge: 112
Registriert: Samstag 22. Juli 2006, 13:38

Hey,
ich hab die milisekunden entfernen wollen, und noch eine neue Spalte dazu machen wollen, und irgendwie zeigt er mir jetzt den Fehler
Traceback (most recent call last):
File "C:\Dokumente und Einstellungen\Admin\Desktop\Python_script.py", line 24, in -toplevel-
d, m, y = ( int(val) for val in row[2].split(".") )
File "C:\Dokumente und Einstellungen\Admin\Desktop\Python_script.py", line 24, in <generator expression>
d, m, y = ( int(val) for val in row[2].split(".") )
ValueError: invalid literal for int(): 23:11:35:331

Code: Alles auswählen

import psycopg2 
import csv 
import datetime 


# Datenbank-Connection und -Cursor erstellen 
conn = psycopg2.connect(user = "Import", password = "import", database = "GBC") 
cur = conn.cursor() 

# CSV-Datei öffnen 
f = file("neu.csv", "r") 

# CSV-Datei dem Parser übergeben 
csvdata = csv.reader(f, delimiter = ';') 

# Jede, nicht leere, Zeile durchlaufen 
for row in ( row for row in csvdata if row ): 
    # 
    # Daten vorbereiten (in den korrekten Datentyp umwandeln) 
    # 
    data = []
    data += row[1]
    # Datum 
    d, m, y = ( int(val) for val in row[2].split(".") ) 
    data.append(datetime.date(y, m, d)) 
    # Uhrzeit 
    H, M, S = ( int(val) for val in row[3].split(":") ) 
    data.append(datetime.time(H, M, S,)) 
    # Eingangsport und Ausgangsport, Eingangsnummer und Ausgangsnummer 
    data += [int(row[4]), int(row[5]), row[6] or None, row[7] or None] 
    # Dauer 
    try: 
        data.append(int(row[8])) 
    except ValueError: 
        data.append(None) 
    # Fehler 
    data.append(row[9].strip()) 
    
    # 
    # Daten in DB schreiben 
    # 
    sql = """ 
    INSERT INTO call (
	callrefnummer 
        datum, 
        uhrzeit, 
        eingangsport, 
        ausgangsport, 
        A-Nummer, 
        B-Nummer, 
        dauer, 
        Releasecode 
    ) VALUES ( 
        %s, %s, %s, %s, %s, %s, %s, %s 
    ) 
    """ 
   
    try: 
        cur.execute(sql, data) 
    except psycopg2.IntegrityError, errdata: 
        if "c_call_unique" in str(errdata): 
            conn.rollback() 
        else: 
            raise 
    # Commit nach jedem "execute", da bei Fehler ein "Rollback" durchgeführt wird. 
    
conn.commit() 

# CSV-Datei schließen 
f.close() 

# Anzeigen 
sql = "SELECT * FROM call" 
cur.execute(sql) 
print cur.fetchall() 

# Datenbankverbindung trennen 
cur.close() 
conn.close()    
cur.execute(sql, data) 
    
# Commit 
conn.commit() 

# CSV-Datei schließen 
f.close() 

# Anzeigen 
sql = "SELECT * FROM daten" 
cur.execute(sql) 
print cur.fetchall() 

# Datenbankverbindung trennen 
cur.close() 
conn.close()

CREATE TABLE call
(
callrefnummer varchar(50) NOT NULL,
datum date,
uhrzeit time,
eingangsport int4,
ausgangsport int4,
eingangsnummer varchar(50),
ausgangsnummer varchar(50),
dauer int4,
releasecode varchar(50),
CONSTRAINT call_pkey PRIMARY KEY (callrefnummer)
)
WITHOUT OIDS;
ALTER TABLE call OWNER TO "Tim";

und die Quelldatei sieht jetzt so aus
18471;21.07.2006;23:17:48:057;5;11;966506485768;22796581027;;CAU_NCC
18472;21.07.2006;23:18:16:107;5;11;33147700610;22796587000;;CAU_NOCAV
18473;21.07.2006;23:21:21:814;5;11;21851620113;22796589192;11762;CAU_NCC

Danke schon ma, hab jetzt schon viel rumprobiert aber net wirklich was gefunden


Gruß TIm
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

BoOnOdY hat geschrieben:ich hab die milisekunden entfernen wollen, und noch eine neue Spalte dazu machen wollen,
Hi Tim!

1. Die Nummerierung der Einträge einer Liste beginnt bei 0 und nicht bei 1.
2. Wenn du nicht weißt, warum der Fehler auftritt, dann schreibe dir ein paar Print-Anweisungen in den Quellcode, damit du nachvollziehen kannst, welchen Wert du gerade bearbeitest. Du kannst auch mit einer guten IDE arbeiten und den Code darin debuggen.

z.B.:

Code: Alles auswählen

print "row:", row
print "row[0]:", row[0]
print "row[1]:", row[1]
So etwas wirkt Wunder. Dann würdest du raus bekommen, dass du die falschen Listeneinträge heranziehst.

Wenn du einen Text wie z.B. "13:11:056" durch die Anweisung split(":")
trennst, dann musst du das Ergebnis entweder einer oder drei Variablenamen zuweisen. Das Ergebnis lässt sich nicht zwei Variablen zuweisen, da du drei Werte zurück bekommst -- nicht zwei.

Code: Alles auswählen

H, M, ms = "13:11:056".split(":") # OK
H, M = "13:11:056".split(":")       # Fehler
Lass also ``H, M, ms`` auf der linken Seite stehen und verwende ``ms`` einfach nicht weiter.

Noch Fragen?

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

gerold hat geschrieben:- text ??? --> varchar(maximale Feldgröße)

Code: Alles auswählen

#CREATE TABLE call (
[...]
#   eingangsnummer varchar(50), 
Hi!

:oops:
Richtigstellung:

Ich hatte fälschlicherweise angenommen, dass bei PostgreSQL der Datentyp TEXT gleich wie bei MsSQL nicht indizierbar ist und dessen Daten nicht in der Tabelle sondern in einem eigenen Speicherbereich gehalten werden. Deshalb hatte ich von TEXT abgeraten und stattdessen VARCHAR empfohlen.

In der Dokumentation zu PostgreSQL steht aber eindeutig, dass die Datentypen "VARCHAR", "CHAR" und "TEXT" gleich schnell sind. Auch konnte ich ein Beispiel entdecken, in dem eine Spalte vom Datentyp "TEXT" indiziert wurde. Also muss ich zugeben, dass bei PostgreSQL der Datentyp "TEXT" keine schleche Wahl für jegliche Art von Texten ist.

lg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
BoOnOdY
User
Beiträge: 112
Registriert: Samstag 22. Juli 2006, 13:38

Ich hätt noch ne Kleinigkeit:

Gibt es irgend ein Python Befehl, der sagt:

Wenn die Fehlerrückgabe aus der PostgreSQL war, dass der Primary Key Doppelt war, dann schreibe den Datensatz in ein "log" file und mache normal weiter.

Gruß Tim :)
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

BoOnOdY hat geschrieben:Wenn die Fehlerrückgabe aus der PostgreSQL war, dass der Primary Key Doppelt war, dann schreibe den Datensatz in ein "log" file und mache normal weiter.
Hi Tim!

Provoziere den Fehler herbei und untersuche ihn.

Wenn es einen Fehler beim INSERT gibt, dann wird dieser im "except"-Block des Programmes verarbeitet. Du musst im "except"-Block nur prüfen, ob es auch wirklich der richtige Fehler ist und nicht irgendein anderer. Schau dir also an, welchen Fehlertyp und was du als Fehlermeldung zurück bekommst und untersuche die Variable, die die Fehlermeldung enthält.

Wenn du also weißt, dass es sich um den gewünschten Fehler handelt, dann kannst du alles was du willst, zu diesem Zeitpunkt, in eine Textdatei schreiben.

Wo liegt das Problem? Beim Erkennen des Fehlers oder beim Schreiben in eine Textdatei?

lg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
BoOnOdY
User
Beiträge: 112
Registriert: Samstag 22. Juli 2006, 13:38

Hy,
also mir gehts darum wie ich das dann in ne text datei schreibe.

Ist dieses "rollback" einfach der ausdruck dafür, das er weiter macht und den Datensatz überspringt?

Gruß Tim :)
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

BoOnOdY hat geschrieben:also mir gehts darum wie ich das dann in ne text datei schreibe.

Ist dieses "rollback" einfach der ausdruck dafür, das er weiter macht und den Datensatz überspringt?
Hi Tim!

Wie du in eine Textdatei schreiben kannst, das erklärt dir jedes normale Python-Tutorial.

Was es mit dem Rollback auf sich hat, das erkläre ich jetzt mal.

Man kann Datenbankanweisungen einzeln ausführen oder mehrere Anweisungen zusammenfassen.

Mit ``BEGIN TRANS``, ``BEGIN TRANSACTION`` oder wie bei PostgreSQL mit ``BEGIN`` wird so ein Anweisungsblock eingeleitet.

Mit ``COMMIT TRANS``, ``COMMIT TRANSACTION`` oder wie bei PostgreSQL mit ``COMMIT`` wird so ein Anweisungsblock abgeschlossen.

So lange die Anweisung ``COMMIT`` nicht ausgeführt wurde, werden die Änderungen nicht öffentlich. Beendet der Benutzer die Verbindung zur Datenbank ohne vorher den Block mit ``COMMIT`` abzuschließen, wird alles was innerhalb dieses Blockes geändert wurde einfach verworfen.

Die Änderungen die innerhalb eines solchen Blocks passieren, werden erst dann für andere, angemeldete Benutzer sichtbar, wenn der Block mit ``COMMIT`` abgeschlossen wurde.

Tritt ein Fehler während der Abarbeitung der SQL-Anweisungen eines solchen Blockes auf, dann werden alle vorhergehenden Änderungen, die innerhalb dieses Blocks passiert sind, rückgängig gemacht.

So ein Anweisungsblock könnte so aussehen:

Code: Alles auswählen

BEGIN;
INSERT INTO adressen (vorname, nachname) VALUES ('Gerold', 'Penz');
INSERT INTO adressen (vorname, nachname) VALUES ('Ludwig', 'Bucher');
COMMIT;
Tritt z.B. beim Hinzufügen des Datensatzes "Ludwig Bucher" ein Fehler auf, dann wird auch der Datensatz "Gerold Penz" nicht hinzugefügt.

psycopg2 sendet die Anweisung ``BEGIN`` bereits beim Initialisieren der Connection oder des Cursors (genau weiß ich es jetzt nicht mehr -- ist aber auch egal). Wenn du also eine ändernde SQL-Anweisung wie z.B. ``UPDATE`` oder ``INSERT`` ausführst, dann musst du danach nur noch das ``COMMIT`` senden. Das funktioniert mit der Anweisung ``conn.commit()``. Dieses ``conn.commit()`` schicht jetzt nicht nur ein ``COMMIT`` an die Datenbank, sondern auch ein neues ``BEGIN``. Damit ist wieder eine neue Transaktion eröffnet. Möchtest du jetzt wieder etwas ändern, dann genügt wieder ein einfaches ``conn.commit()``.

Möchtest du gezielt alle Änderungen eines Blockes verwerfen, dann kannst du ein ``ROLLBACK`` an die Datenbank schicken. Das funktioniert aber nur innerhalb eines Blocks. Wenn der Block einmal mit ``COMMIT`` abgeschlossen wurde, ist es zu spät. Dieses ROLLBACK kannst du ziemlich einfach mit der Anweisung ``conn.rollback()`` an die Datenbank schicken. Aber, genauso wie auch ein ``conn.commit()`` eine neue Transaktion eröffnet, eröffnet auch ein ``conn.rollback()`` eine neue Transaktion. Der Unterschied ist nur, dass vorher die Änderungen des Blocks, verworfen werden.

Das ist auch der Grund, weshalb ich im vorherigen Beispiel nach jeder Änderung ein ``conn.commit()`` ausführe. Tritt nämlich ein Fehler auf, möchte ich nicht alle Änderungen rückgängig machen, sondern nur das Hinzufügen des aktuellen Datensatzes abbrechen und dann mit dem nächsten Datensatz weiter machen.

Allerdings ist in so einem Fall bereits ein Fehler in der Datenbank aufgetreten. Die Datenbank beendet somit den Block, also die Transaktion, und erwartet ein neues ``BEGIN`` von der Client-Anwendung. Mit ``conn.commit()`` kann man eine fehlerhafte Transaktion nicht abschließen. Da zeigt uns PostgreSQL den Vogel und teilt uns mit, dass es ja einen Fehler gegeben hat, den PostgreSQL nicht abschließen kann. Deshalb beginne ich die neue Transaktion mit ``conn.rollback()``, was der Datenbank mitteilt, dass die letzte Änderung verworfen werden kann. Da ``conn.rollback()`` zusätzlich auch eine neue Transaktion eröffnet, steht einem erneuten Schleifendurchlauf nichts mehr im Weg.

lg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Antworten