seltsame Fehlermeldung in sqlite3

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Cortez
User
Beiträge: 13
Registriert: Montag 31. Dezember 2018, 15:28

Samstag 5. Januar 2019, 18:19

Hallo,

ich habe folgendes kleine Skript geschrieben (eine kleine Datenbank in sqlite3, die Personendaten speichern kann). Leider bekomme ich, nachdem ich einen datensatz eingegeben habe, stets folgende Fehlermeldung:

Traceback (most recent call last):
File "./verwaltung.py", line 46, in <module>
personaldateneingeben(id, name, vorname, anschrift, telefon, mail)
File "./verwaltung.py", line 21, in personaldateneingeben
VALUES(?,?,?,?,?,?) """, (id, name, vorname, anschrift, telefon, mail))
sqlite3.InterfaceError: Error binding parameter 0 - probably unsupported type
.

Das Verrückte ist, dass das Ganze jedoch wunderbar funktioniert hat, bis ich das Auswahlmenü am anfang programmiert habe - Dateneingabe oder Programmende. Warum geht das jetzt nicht mehr?
Bin um jeden Tipp dankbar.

Code: Alles auswählen

#!/usr/src/Python-3.7.2/python

import sqlite3

datenbank = sqlite3.connect('verwaltung.db')
print ("Datenbank geöffnet")


datenbank.execute(""" CREATE TABLE IF NOT EXISTS Personen (
        ID INT PRIMARY KEY NOT NULL,
        NAME TEXT NOT NULL,
        VORNAME TEXT NOT NULL,
        ANSCHRIFT TEXT,
        TELEFON TEXT,
        MAIL TEXT)""")


def personaldateneingeben(id, name, vorname, anschrift, telefon, mail):
    
    datenbank.execute (""" INSERT INTO Personen(ID, NAME, VORNAME, ANSCHRIFT, TELEFON, MAIL)
        VALUES(?,?,?,?,?,?) """, (id, name, vorname, anschrift, telefon, mail))
  
    datenbank.commit()
 
print ("Was möchten Sie tun")
print()
print("Daten anlegen=1")
print()
print("Programmende=2")
print()


while True:
    
    eingabe = input ("Bitte eingeben ")
    if eingabe == "1":
        i = 1
        while True:
            print()
            name = input ("bitte Zunamen eingeben")
            vorname = str(input ("bitte Vornamen eingeben"))
            anschrift = str(input("bitte Anschrift eingeben oder [Enter], falls unbekannt"))
            telefon = str(input("bitte Telefonnummer eingeben oder [Enter], falls unbekannt"))
            mail = str(input("bitte mailadresse angeben oder [Enter],falls unbekannt"))

            personaldateneingeben(id, name, vorname, anschrift, telefon, mail)
            print()
            eingabe = input("Noch eine Person anlegen? [j] oder [n]")

            if eingabe == "j":
                id=int(id)+1
            elif eingabe == "n":
                break
            else:
             #eingabe2 =  input("Bitte [j] oder [n] eingeben")
                while True:
                    eingabe2 =  input("Bitte [j] oder [n] eingeben")
                    if eingabe2 == "j":
                        id=int(id)+1
                        break
                    if eingabe2 == "n":
                        break
                if eingabe2 == "n":
                    break
        
    if eingabe == "2":
        print ("Auf Wiedersehen")
        break
    
datenbank.close()
Sirius3
User
Beiträge: 9017
Registriert: Sonntag 21. Oktober 2012, 17:20

Samstag 5. Januar 2019, 18:27

`id` ist die eingebaute id-Funktion, die Du natürlich nicht in eine Datenbank schreiben kannst.

Auch wenn SQLite das zuläßt, sollte man sich trotzdem einen Cursor erzeugen, auf dem man `execute` aufruft. Funktionen sollten alles was sie brauchen über ihre Argumente bekommen, also auch `datenbank`.
Die ganzen `str`-Aufrufe sind überflüssig und können weg.
Irgendwie sind die vielen verschachtelten while-Schleifen zu verschachtelt, da ist ein bißchen doppelter Code drin.
Benutzeravatar
__blackjack__
User
Beiträge: 1866
Registriert: Samstag 2. Juni 2018, 10:21

Samstag 5. Januar 2019, 19:21

Cortez: Warum schreibst Du die Spaltennamen im SQL alle GROSS? Wenn man die klein schreibt, lassen sie sich deutlich leichter von den Datentypen und anderen SQL-Schlüsselwötern unterscheiden.

Das NOT NULL beim PRIMARY KEY ist überflüssig.

Die ID braucht man dann auch gar nicht mehr selbst angeben, da kümmert sich SQLite schon drum.


Auf Modulebene sollte nur Code stehen der Konstanten, Funktionen, und Klassen definiert. Das Hauptprogramm steht üblicherweise in einer Funktion die `main()` heisst. Dannistmanauchgezwungen`datenbank`alsArgumentandie`personaldateneingeben()`-Funktionzuübergeben. Liest sich blöd ohne Leerzeichen? Funktionsnamen ohne Unterstriche zwischen den Worten auch. ;-)
Having more money does not insure happiness. People with ten million dollars are no happier than people with nine million dollars. – Hobart Brown
Cortez
User
Beiträge: 13
Registriert: Montag 31. Dezember 2018, 15:28

Sonntag 6. Januar 2019, 00:11

Danke erstmal für die, wie immer, rasche und kompetente Hilfe.

Habe den Fehler gefunden.
@Black_Jack: Ich habe irgendwie fälschlicherweise gedacht, dass sql-Spalten großgeschrieben werden müssen. Naja habs abgeändert. :)

Stehe jetzt allerdings vor einem Problem, bei dem ihr mir vielleicht auch helfen könnt:

Und zwar würde mich interessieren, ob man Tabellenspalten auch dynamisch(vielleicht der falsche Ausdruck) befüllen kann.

Nehmen wir an, ich hätte eine Tabelle mit 10 Spalten, von denen aber nicht immer alle befüllt werden sollen (in unserem Beispiel könnte das eine Faxnummer oder 2. Mailadresse sein, was eventuell nicht jeder hat). Kann ich das dem Skript irgendwie geschickt klarmachen?
Sirius3
User
Beiträge: 9017
Registriert: Sonntag 21. Oktober 2012, 17:20

Sonntag 6. Januar 2019, 00:29

Für die fehlenden Werte übergibst Du einfach None.
Cortez
User
Beiträge: 13
Registriert: Montag 31. Dezember 2018, 15:28

Sonntag 6. Januar 2019, 12:46

Danke dir für den Tipp.

Kann ich diese None-Werte dann auch aus der Datenbank lesen um im Programm damit arbeiten zu können (also mit Schleifen oder Ähnlichem) - z.B. dass die Schleife überspringt, wenn ein leerer Wert erscheint
Benutzeravatar
sls
User
Beiträge: 304
Registriert: Mittwoch 13. Mai 2015, 23:52
Wohnort: Tannhauser Gate

Sonntag 6. Januar 2019, 13:05

Cortez hat geschrieben:
Sonntag 6. Januar 2019, 12:46
Kann ich diese None-Werte dann auch aus der Datenbank lesen um im Programm damit arbeiten zu können (also mit Schleifen oder Ähnlichem) - z.B. dass die Schleife überspringt, wenn ein leerer Wert erscheint
Ja, Datenbanken behandeln diesen Wert i.d.R. immer als NULL, was äquivalent zu Python's None ist.
With great processing power comes great responsibility.
Benutzeravatar
__blackjack__
User
Beiträge: 1866
Registriert: Samstag 2. Juni 2018, 10:21

Sonntag 6. Januar 2019, 13:33

@Cortez: Wobei man natürlich auch gleich die Datenbankabfrage so gestalten kann, das die Werte gar nicht erst geliefert werden wenn man sie im Programm sowieso nur überspringen würde.
Having more money does not insure happiness. People with ten million dollars are no happier than people with nine million dollars. – Hobart Brown
Benutzeravatar
snafu
User
Beiträge: 5695
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Sonntag 6. Januar 2019, 13:35

Sirius3 hat geschrieben:
Samstag 5. Januar 2019, 18:27
`id` ist die eingebaute id-Funktion, die Du natürlich nicht in eine Datenbank schreiben kannst.
Nicht wirklich. id wird durch den Funktionsparameter überschrieben und hält somit das, was der Funktion an dieser Stelle übergeben wurde. Ratsam ist das Überschreiben eingebauter Funktionen natürlich trotzdem nicht, wobei ich es im Falle von id schon öfter gesehen habe.
Benutzeravatar
__blackjack__
User
Beiträge: 1866
Registriert: Samstag 2. Juni 2018, 10:21

Sonntag 6. Januar 2019, 13:42

@snafu: Doch wirklich, denn der Funktion wird als erstes Argument die eingebaute `id()`-Funktion übergeben. :-)
Having more money does not insure happiness. People with ten million dollars are no happier than people with nine million dollars. – Hobart Brown
Cortez
User
Beiträge: 13
Registriert: Montag 31. Dezember 2018, 15:28

Sonntag 6. Januar 2019, 20:23

Ok, eure Antworten haben bei mir jetzt einige Unklarheiten hervorgerufen.

Ich versuche mal zu erklären, was ich gerne möchte:

Sagen wir mal, ich habe eine Tabelle mit 10 Feldern. Davon werden nicht immer alle Felder befüllt (hängt von der Zeile ab).
Mein Programm fragt per Schleife den Benutzer nach den werten (wenn ein Feld leer bleibt, soll er halt enter oder so drücken). Die Werte werden dann in eine Liste gespeichert und in die Tabelle eingetragen.

So, wie krieg ich das mit dem Null setzen nun am Besten hin? Meine Idee wäre folgende: der Liste halt überall da, wo nix vom User eingegeben wurde, den Wert Null geben. Und danach irgendwie Query (muss mich noch schlau machen, ob und wie das geht) starten, wo eben alle Werte, die 0 sind, gefunden und gelöscht werden.
Ist das ein praktikabler Weg oder, wie man sagt, mit Kanonen nach Spatzen geschossen?
Sorry für die dummen Fragen, aber mein sqlite-Wissen beschränkt sich auf das, was youtube-Tutorials so hergeben...
Benutzeravatar
__blackjack__
User
Beiträge: 1866
Registriert: Samstag 2. Juni 2018, 10:21

Sonntag 6. Januar 2019, 20:35

@Cortez: Da wo der Benutzer nichts angegeben hat verwendest Du `None` als Wert. Und bei der Abfrage bekommst Du überall wo Du `None` angegeben hast – man glaubt es kaum – `None` als Wert aus der Datenbank. Ich verstehe jetzt nicht so ganz welches Problem Du damit hast?
Having more money does not insure happiness. People with ten million dollars are no happier than people with nine million dollars. – Hobart Brown
Cortez
User
Beiträge: 13
Registriert: Montag 31. Dezember 2018, 15:28

Sonntag 6. Januar 2019, 21:56

Ich habe fürmein Anliegen mal ein vereinfachstes Skript geschrieben (Prinzip ist aber dasGleiche)

Code: Alles auswählen

import sqlite3

db = sqlite3.connect('Testdatenbank')

db.execute(""" CREATE TABLE IF NOT EXISTS Werte (
        Wert1 INT,
        Wert2 INT,
        Wert3 INT,
        Wert4 INT,
        Wert5)""")

i = 1
Werteliste = []
While i < 6:
    var = input(" Bitte Wert eingeben")
    if var == "Abbruch":
        break
    elif var == " ":
        Werteliste.append(0)
    else:
        Werteliste.append(var)
    i = i+1
    
db.execute(""" INSERT INTO Werte(Wert1, Wert2, Wert3, Wert4, Wert5) VALUES(?,?,?,?,?) """, (Werteliste[0], Werteliste[1], Werteliste[2], Werteloiste[3], Werteliste[4]))

db.close()

Also ich kriegs irgendwie nicht hin, anstelle den 0-Werten in der Liste dann None zu übermitteln.

By the way: Falls ein Benutzer nun mehr als 5 Werte eingeben wollte - kann sqlite3 in solch einem Fall auch dynamisch neue Felder hinzufügen oder muss man das bei der Tabellenerstellung schon machen und danach geht nichts mehr?
Sirius3
User
Beiträge: 9017
Registriert: Sonntag 21. Oktober 2012, 17:20

Sonntag 6. Januar 2019, 22:25

Warum ist Wert5 kein INT? Und warum schreibst Du dann nur Texte in die Datenbank? 0 ist nicht None. Wenn Du Abbruch eingibst, dann ist die Liste zu kurz und es gibt später Fehler. Die while-Schleife sollte mit kleinem w geschrieben werden und besser eine for-Schleife sein.
Und nein, ein Datenbankschema ist fix. Aber das Beispiel hat auch nichts mit Deinem vorherigen Problem zu tun.
Cortez
User
Beiträge: 13
Registriert: Montag 31. Dezember 2018, 15:28

Sonntag 6. Januar 2019, 22:56

Ja, wert5 soll auch ein int sein. Und im fertigen Programm läuft noch einmal eine Schleife, die überall da, wo noch kein Wert ist, auch eine 0 einfügt.
Dass 0 nicht NONE ist, ist mir klar. Und das ist ja das Problem. Ich möchte, dass die Zahlen in die Tabelle werden, eben außer da, wo aufgrund fehlender Nutzereingaben der Liste eine 0 gegeben wurde. Und in der Tabelle sollen diese Nuller zugunsten des Leerwertes NONE getauscht werden. Und ich weiß nicht wie. Feldernamen können ja nicht als Variablen an den SQL-Befehl übergeben werden - sonst wärs mit Schleife einfach.
Antworten