Leere Felder in SQLite3

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
Antworten
hans.py
User
Beiträge: 6
Registriert: Dienstag 1. August 2006, 10:59
Wohnort: Baden Württemberg

Freitag 6. Juli 2007, 22:32

Hallo

Ich habe Daten in einer DBF Datenbank, die ich mittels dbfpy auslese und in eine SQLite3 Datenbank einlesen möchte (zwecks besserer Nachverarbeitung mittels SQL). Das Problem ist nur, daß nicht immer in jedem Feld der Ursprungstabelle ein Wert steht, deshalb erscheint auch die folgende Fehlermeldung::(

sqlite3.ProgrammingError: Incorrect number of bindings supplied. The current statement uses 19, and there are 0 supplied.

In Wirklichkeit sind es 31 Spalten aber ich habe es auf 19 reduziert, aber auch dort kommt es vor, daß es leere Spalten in der Ursprungstabelle gibt. Leider ist schon der erste Eintrag nicht vollständig, somit wird nichts in die SQLite Datenbank geschrieben.

Ich habe mir schon überlegt, ob man bei jeder Spalte vorher schaut, ob was drin steht und sie dann überspringt, aber das scheint mir zu aufwendig...

Beispielcode kann ich bei Bedarf schicken, aber es scheint sich hier ja um ein generelles Datenbankproblem im Umgang mit leeren Feldern zu handeln.

Weiß jemand, wie man so ein Problem einfach umgehen kann?

Ach ja: Ich benutze Python 2.5 unter WinXP.

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

Freitag 6. Juli 2007, 22:55

hans.py hat geschrieben:Das Problem ist nur, daß nicht immer in jedem Feld der Ursprungstabelle ein Wert steht
Hallo Hans!

Du hast als Quelle eine Tabelle mit einer **fixen** Feldanzahl. Auch das Ziel ist eine Tabelle mit einer **fixen** Feldanzahl.

Lösung: Hole **alle** benötigten Felder aus der Quelle und schreibe **alle** diese Felder in das Ziel.

Damit auch leere Werte (Im Datenbank-Slang auch NULL genannt.) in ein Feld der Zieltabelle geschrieben werden können, muss das Zielfeld darauf vorbereitet werden.

Dieses Beispiel erstellt eine Tabelle mit zwei Feldern. Beide Felder dürfen NULL enthalten:

Code: Alles auswählen

CREATE TABLE zieltabelle (
  vorname TEXT NULL,
  nachname TEXT NULL
)
Jetzt kannst du die Zieltabelle befüllen. Egal ob ein Feld NULL enthält.

Code: Alles auswählen

sql = """
INSERT INTO zieltabelle (
  vorname, nachname
) VALUES (
  ?, ?
)"""
for row in quelldaten:
    sqlite_conn.execute(sql, row)
sqlite_conn.commit()
Dabei gehe ich jetzt davon aus, dass quelldaten entweder ein Datenbankcursor mit Daten, oder ein Tupel in dieser Form ist:

Code: Alles auswählen

quelldaten = (
    ("EinVorname", "EinNachname"),
    ("NochEinVorname", None),
    ("WiederEinVorname", "WiederEinNachname"),
)
Das ``None`` ist mit NULL gleichzusetzen. Es wird aber beim Einfügen kein Fehler ausgelöst, da das Tabellenfeld NULL erlaubt.

EDIT:

Gleich noch ausprobiert:

Code: Alles auswählen

>>> import sqlite3
>>> conn = sqlite3.connect(":memory:")
>>> sql="""
...     CREATE TABLE zieltabelle (
...     vorname TEXT NULL,
...     nachname TEXT NULL
...     )"""
>>> conn.execute(sql)
<sqlite3.Cursor object at 0x01B969B0>
>>> conn.commit()
>>> sql = """
...     INSERT INTO zieltabelle (
...     vorname, nachname) VALUES (
...     ?, ?)"""
>>> quelldaten = (
...     ("EinVorname", "EinNachname"),
...     ("NochEinVorname", None),
...     ("WiederEinVorname", "WiederEinNachname"),
... )
>>> for row in quelldaten:
...     conn.execute(sql, row)
...     
<sqlite3.Cursor object at 0x01B967D0>
<sqlite3.Cursor object at 0x01B969B0>
<sqlite3.Cursor object at 0x01B967D0>
>>> conn.commit()
>>> sql = """SELECT * from zieltabelle"""
>>> cur = conn.cursor()
>>> cur.execute(sql)
<sqlite3.Cursor object at 0x01B969E0>
>>> for row in cur:
...     print repr(row)
...     
(u'EinVorname', u'EinNachname')
(u'NochEinVorname', None)
(u'WiederEinVorname', u'WiederEinNachname')
>>> 
Man könnte in diesem Fall auch mit ``cur.executemany(sql, quelldaten)`` arbeiten, da das aber nicht ideal ist, wenn du die Daten zeilenweise von einer anderen Datenbank holst, habe ich das Beispiel so geschrieben, wie es jetzt ist.

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
hans.py
User
Beiträge: 6
Registriert: Dienstag 1. August 2006, 10:59
Wohnort: Baden Württemberg

Samstag 7. Juli 2007, 11:58

Vielen Dank Gerold für deine schnelle Hilfe.

Ich dachte, daß wenn man nicht explizit "NOT NULL" angibt, daß dann NULL-Werte zulässig sind. Ich werde es heute abend gleich mal ausprobieren.

Viele Grüße
Hans
hans.py
User
Beiträge: 6
Registriert: Dienstag 1. August 2006, 10:59
Wohnort: Baden Württemberg

Samstag 7. Juli 2007, 15:17

So jetzt hab ich es ausprobiert, aber ich glaube nicht, daß es der Fehler war. Ich habe nämlich mittlerweile festgestellt, daß die leeren Felder der DBF-Datei beim auslesen in "0.0" umgewandelt werden. Das ist aber nicht gewünscht, da es sich bei der Datenbank um Daten einer Wetterstation handelt. Und wenn da der Sensor ausfällt bzw. nicht vorhanden ist, soll ja keine Temperatur von 0.0 Grad zurückgegeben werden. Das Problem ist aber erstmal zweitrangig.

Das andere ist, daß der Fehler wohl bei dem SQL Befehl "INSERT INTO" liegt.
Hier mal ein Stück Beispielcode:

Code: Alles auswählen

#Auslesen der DBF Daten
db = dbf.Dbf("NexusOrg.dbf")
connection = sqlite3.connect("WetterNexus.db")

cursor = connection.cursor()
zaehler = 0
for rec in db:
    datum,zeit = du.wtopy(rec[0])
    ch0_deg = rec[1]
    ch0_rf = rec[2]
    ch0_dew = rec[3]
    ch1_deg = rec[4]
    ch1_rf = rec[5]
    ch1_dew = rec[6]
    ch2_deg = rec[7]
    ch2_rf = rec[8]
    ch2_dew = rec[9]
    ch3_deg = rec[10]
    ch3_rf = rec[11]
    ch3_dew = rec[12]
    ch4_deg = rec[13]
    ch4_rf = rec[14]
    ch4_dew = rec[15]
    ch5_deg = rec[16]
    ch5_rf = rec[17]
    ch5_dew = rec[18]
    dru_loc = rec[19]
    dru_abs = rec[20]
    fcast = rec[21]
    wchill = rec[22]
    wtemp = rec[23]
    wgust = rec[24]
    wspeed = rec[25]
    wdir = rec[26]
    rain_sum = rec[27]
    ecode = rec[28]
    id = zaehler
    zaehler += 1
    print zaehler
    print datum,zeit,ch0_deg,ch0_rf,ch0_dew,ch1_deg,ch2_deg,wtemp,dru_loc,dru_abs
    
    # insert DATA in SQLite3 DB
     
    cursor.execute("""INSERT INTO "WetterNexus"(id, date, time, t0, f0, td0,
                    t1, f1, td1, t2, f2, td2, t3, f3, td3, t4, f4, td4, t5, f5, td5,
                    druckl, druckabs, fc, wchill, wtemp, wgust, wspeed, wdir,
                    rainsum, errcode)
                    VALUES (:id, :datum, :zeit, :ch0_deg, :ch0_rf, :ch0_dew, :ch1_deg, :ch1_rf, :ch1_dew, 
                    :ch2_deg, :ch2_rf, :ch2_dew, :ch3_deg, :ch3_rf, :ch3_dew,
                    :ch4_deg, :ch4_rf, :ch4_dew, :ch5_deg, :ch5_rf, :ch5_dew,
                    :dru_loc, :dru_abs, :fcast, :wchill, :wtemp, :wgust, :wspeed, :wdir, :rain_sum, :ecode)""")


cursor.close()
connection.close() 
Das habe ich so in einem Beispiel gesehen, aber ich vermute daß das mit den Doppelpunkten das Problem ist. Lasse ich sie weg, dann kommt der Fehler, daß z.B. die Spalte id nicht bekannt ist.
Ich habe dann ein anderes Besp. gesehen und den Code abgeändert:

Code: Alles auswählen

cursor.execute("""INSERT INTO WetterNexus(id, date, time, t0, f0, td0,
                    t1, f1, td1, t2, f2, td2, t3, f3, td3, t4, f4, td4, t5, f5, td5,
                    druckl, druckabs, fc, wchill, wtemp, wgust, wspeed, wdir,
                    rainsum, errcode)
                    VALUES (%d, %s, %s, %f, %d, %f, %f, %d, %f, %f, %d, %f, %f, %d, %f,
                    %f, %d, %f, %f, %d, %f, %f, %f, %d, %f, %f, %f, %f, %f, %f, %f)""", (id, datum,
                    zeit, ch0_deg, ch0_rf, ch0_dew, ch1_deg, ch1_rf, ch1_dew, 
                    ch2_deg, ch2_rf, ch2_dew, ch3_deg, ch3_rf, ch3_dew,
                    ch4_deg, ch4_rf, ch4_dew, ch5_deg, ch5_rf, ch5_dew,
                    dru_loc, dru_abs, fcast, wchill, wtemp, wgust, wspeed, wdir, rain_sum, ecode)) 
Aber auch hier kommt ein Fehler, diesmal:

sqlite3.OperationalError: near "%": syntax error

Ich hoffe, daß mir auch diesmal jemand weiterhelfen kann. Falls nötig, kann ich noch die Tabellenerstellung posten, aber die funktioniert ja.

Viele Grüße Hans
BlackJack

Samstag 7. Juli 2007, 16:13

Du hast Platzhalter für Zeichenketten-Formatierung in die SQL-Anweisung geschrieben, das geht nicht. Es gibt ein paar Datenbankmodule die '%s' dafür benutzen, das hat aber nichts mit dem ``%``-Operator auf Zeichenketten zu tun.

Das `sqlite3`-Modul benutzt Fragezeichen als Platzhalter.

Code: Alles auswählen

In [11]: from sqlite3 import dbapi2 as sqlite

In [12]: sqlite.paramstyle
Out[12]: 'qmark'
hans.py
User
Beiträge: 6
Registriert: Dienstag 1. August 2006, 10:59
Wohnort: Baden Württemberg

Samstag 7. Juli 2007, 19:52

Vielen Dank BlackJack. Das war ein entscheidender Hinweis!

Jetzt funktioniert das einlesen und ich kann weitermachen... :D
Antworten