insert in sqllite DB schlägt fehl

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MariaDB/MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
Antworten
erdmulch
User
Beiträge: 230
Registriert: Samstag 17. Juli 2010, 19:50

Hallo zusammen,

ich habe folgende sqllite3.db:

id = integer primary
timestamp = datetime
name =varchar(200)
measurement = real

Hier ist mein code um die Datenbank zu befüllen:

Code: Alles auswählen

insert_new_line_in_temperature_sensor_table("/home/pi/Database/db.sqlite3", "sensordata", "2018-06-06", "Sensor1", "10.5")
Allerdings wird meine Datenbank nicht befüllt.
Ich denke fast, dass es an den Anführungszeichen (") liegt.
der compiler denkt wahrscheinlich, dass es sich immer um ein Strin handelt.
kann es aber sicher nicht sagen, weiß auch nicht wie ich es anders machen soll

der Code an sich müsste eigentlich passen, das muss irgendwas mit den Datentypen zu tun haben

Kann mir jemand helfen?

vielen Dank
Sirius3
User
Beiträge: 17710
Registriert: Sonntag 21. Oktober 2012, 17:20

Was macht denn die Funktion `insert_new_line_in_temperature_sensor_table` genau? Ich denke darin liegt der Fehler. Vielleicht an einem fehlenden `commit`.
erdmulch
User
Beiträge: 230
Registriert: Samstag 17. Juli 2010, 19:50

Hier der Code:

Code: Alles auswählen

#!/usr/bin/python
# -*- coding: utf-8 -*-
 
import sqlite3 as lite
import sys
 
def insert_new_line_in_temperature_sensor_table(PathToDatabase, TableName, 
                                                Timestamp, Temp_MIN, Temp_MAX):
 
    try:
        con = lite.connect(PathToDatabase)
        cur = con.cursor()  
        cur.execute("""
            INSERT INTO %s 
            VALUES( %i , %i, %i)
            """ % (TableName, Timestamp, Temp_MIN, Temp_MAX))
        con.commit()
        print("Werte wurden in die Datenbank geschrieben")
    except lite.Error:
 
        if con:
            con.rollback()
 
            print ("Test")
            sys.exit(1)
 
    finally:
 
        if con:
            con.close() 
 
insert_new_line_in_temperature_sensor_table("/home/pi/Database/db.sqlite3", 
                                            "sensor1", 1445432400, "Test", 1.0)
Benutzeravatar
__blackjack__
User
Beiträge: 13003
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@erdmulch: Die Werte solltest Du nicht als Zeichenketten in eine SQL-Zeichenkette hinein formatieren, sondern SQL und Werte trennen. In das SQL gehören Platzhalter und die Werte werden als zweites Argument an `execute()` übergeben. Das wird mit dem Tabellennamen dann nicht gehen — der sollte aber auch nicht Variabel sein. Wenn es mehrere Sensoren gibt, dann speichert man die Daten nicht in eine Tabelle pro Sensor, sondern alle Daten in gleiche Tabelle, und man speichert jeweils dazu zu welchem Sensor der Wert gehört.

Die ``if con:``-Abfragen sind falsch. Entweder gibt es die Verbindung, dann ist die aber auch immer ”wahr”, oder die Verbindung kam nicht zustande, dann gibt es aber auch den Namen `con` nicht und das rennt dort jeweils in einen `NameError`.

`sqlite3` mit `lite` abzukürzen erscheint mir nicht besonders sinnvoll. Andererseits ist der Funktionsname übermässig lang. Und `line` sollte da eher `row` heissen. Andererseits impliziert ein `insert` das dort eine neue Zeile in der DB entsteht.

`Temp_MIN` hat den Wert "Test"? Komische Temperaturangabe. :-P
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Sirius3
User
Beiträge: 17710
Registriert: Sonntag 21. Oktober 2012, 17:20

@erdmulch: jetzt hast Du ja ein ganz anderes Tabellendesign. Vermeide Abkürzungen: lite ist drei Buchstaben weniger als sqlite3 und wird auch genau ein mal benutzt. con und cur sind auch kryptisch und machen damit den Code schwer lesbar.
Man formatiert weder Tabellennamen in SQL-Statements (der Sensorname gehört in die Tabelle, wie in Deinem oberen Tabellendesign ja auch umgesetzt), noch formatiert man Parameter in SQL-Statements. Dafür gibt es Platzhalter. %i ist zudem falsch für Temperaturen.
Bei INSERTS gibt man die Felder explizit an, statt auf die implizite Reihenfolge zu vertrauen.
Die Fehlerbehandlung ist falsch, da sie den Fehler nur verdeckt und das Programm unsinnigerweise beendet, so dass eine Fehlerbehandlung gar nicht möglich ist. `if con` ist unsinnig, denn entweder ist con definiert, weil connect funktioniert, oder `con` ist nicht definiert und Du bekommst einen NameError.

Was ist denn die Ausgabe, wenn Du die „Fehlerbehandlung“ wegläßt.
erdmulch
User
Beiträge: 230
Registriert: Samstag 17. Juli 2010, 19:50

Hab den code nun angepasst, denke aber das es nachwievor an dem %i liegt
das sollte nämlich ein Timestamp sein

hab den code ein wenig angepasst

Code: Alles auswählen

#!/usr/bin/python
# -*- coding: utf-8 -*-
 
import sqlite3 
import sys
 
def insert_into_database(PathToDatabase, TableName, Timestamp, Name, Value):
 
    try:
        con = sqlite3.connect(PathToDatabase)
        cur = con.cursor()  
        cur.execute("""
            INSERT INTO %s 
            VALUES( %i , %s, %f)
            """ % (TableName, Timestamp, Name, Value))
        con.commit()
        con.rollback()
        con.close()
    except sqlite3.Error:
        print("Hat leider nicht geklappt")
        sys.exit(1)
        
 
insert_into_database("/home/pi/Database/db.sqlite3", "beans_sensor", 1445432400, "Test", 1.0)
Benutzeravatar
__blackjack__
User
Beiträge: 13003
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Nach wie vor solltest Du die Werte da nicht in die Zeichenkette mit dem SQL hinein formatieren. Und der Tabellenname sollte nach wie vor nicht variabel sein.

Weisst Du was `commit()` und `rollback()` machen? Kannst Du erklären was der Code an der Stelle machen soll?

Die Ausnahmebehandlung macht auch so immer noch keinen wirklichen Sinn, ausser das die halt unterdrückt, das man im Ausnahmefall irgendwelche Details über die Ausnahme erfährt.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
erdmulch
User
Beiträge: 230
Registriert: Samstag 17. Juli 2010, 19:50

commit() damit werden die Daten in die Datenbank geschrieben?
Rollback() wenn die Daten nicht hineingeschrieben werden können, weil das File z.B. Korrupt ist

wie das funktionieren soll, weiß ich nicht:
"Nach wie vor solltest Du die Werte da nicht in die Zeichenkette mit dem SQL hinein formatieren. "
Benutzeravatar
__blackjack__
User
Beiträge: 13003
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Du hast da eine Zeichenkette mit SQL und Platzhaltern für den ``%``-Operator und den verwendest Du dann auch. Das ist falsch. Die Zeichenkette sollte Platzhalter für das Datenbankmodul verwenden und keinen ``%``-Operator sondern das zweite Argument von `execute()`. Das ist für Werte in SQL. Schau Dir die Beispiele in der Dokumentation an. Und Tabellennamen sind in SQL keine Werte. Das heisst der Tabellenname sollte an der Stelle nicht variabel sein.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
erdmulch
User
Beiträge: 230
Registriert: Samstag 17. Juli 2010, 19:50

Kann mir da jemand helfen, wie man es richtig macht?

Code: Alles auswählen

#!/usr/bin/python
# -*- coding: utf-8 -*-
 
import sqlite3
import sys
 
def insert_into_database(PathToDatabase, Timestamp, Name, Value):
 
    try:
        con = sqlite3.connect(PathToDatabase)
        cur = con.cursor()  
        cur.execute("""
            INSERT INTO beans_sensor 
            VALUES( %i , %s, %f)
            """ % (Timestamp, Name, Value))
        con.commit()
        con.rollback()
        con.close()
    except sqlite3.Error:
        print("Hat leider nicht geklappt")
        sys.exit(1)
        
 
insert_into_database("/home/pi/Database/db.sqlite3", 1445432400, "Test", 1.0)
Sirius3
User
Beiträge: 17710
Registriert: Sonntag 21. Oktober 2012, 17:20

Wo verstehst Du die Dokumentation nicht? Die Beispiele sind doch ziemlich eindeutig.
Und was ist daran so schwer, die Fehlerbehandlung zu LÖSCHEN?
Antworten