Select und Update von einem int in Sqlite

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MariaDB/MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
Antworten
Paulens
User
Beiträge: 5
Registriert: Freitag 3. März 2017, 00:10

Hallo zusammen :)

hab über Google meinen weg hier her gefunden und hoffe das ihr mir bei meinem Problemchen helfen könnt. Über die Such Funktion konnte ich leider nichts passendes finden :K

Ich habe eine SQlite3 Datenbank und möchte daraus einen int Wert auslesen ihn um 1 hochzählen und dann die Datenbank Updaten.

Allerdings habe ich Probleme den int überhaupt auszulesen. Ich denke das es ein Problem von der Umwandlung vom unicode zu ascii ist. Zumindest war hier der springende Punkt beim String (welche ich dank einem Beitrag hier im Forum lösen konnte :D)

Zu meinem Code:

Code: Alles auswählen

import sqlite3 as lite
import sys

con = lite.connect('testv2.db')

with con:
    cur = con.cursor()
    cur.execute("SELECT besuche FROM Besucher")
        besuche = cur.fetchall()
        visit = []
        for tup in besuche:
            visit = visit + [item.encode('ascii','backslashreplace') for item in tup]
Fehlermeldung:
visit = visit + [item.encode('ascii','backslashreplace') for item in tup]
AttributeError: 'int' object has no attribute 'encode'

Wenn int das Attribut 'encode' nicht hat wie bekomme ich die Daten dann aus der DB raus so das ich mit denen Arbeiten kann? :roll: :K

Vielen Dank schon mal :)
Paul
BlackJack

@Paulens: Ich denke Du versuchst da gerade ein Problem zu lösen das es gar nicht gibt. Du hast da bereits eine ganze Zahl, Datentyp `int`.

Und bei der Zeichenkette hast Du eventuell auch eine falsche Lösung. Die will man eigentlich als `unicode` haben. Zumindest innerhalb des Programms. Die nach ASCII zu wandeln mit allem was nicht ASCII ist als 'backslashreplace' kodiert, ist in der Regel nicht sinnvoll. Denn diese Ersetzung ist recht pythonspezifisch.

Mir ist auch nicht ganz klar was Du mit der `visit`-Liste anfangen möchtest. Du musst ja mindestens noch so etwas wie eine ID in den Datensätzen haben, denn sonst kannst Du die erhöhten Werte hinterher nicht mehr den Besuchern zuordnen von denen die ursprünglichen Werte kamen. Oder vielleicht möchtest Du auch nur einen Wert von einem ganz bestimmten Besucher hochzählen. Dann macht es keinen Sinn die Zahlen für *alle* Besucher abzufragen.

Was Du da mit ``+`` in der Schleife machst, ist ausserdem ziemlich ineffizient. ``+`` erstellt eine neue Liste aus den beiden Operanden. Da werden unnötig viele Listenobjekte als Zwischenergebnisse erstellt und die Daten immer und immer wieder im Speicher herumkopiert. Wenn man Werte an eine Liste anhängen möchte, nimmt man die `append()`-Methode für einzelne Werte oder `extend()` für eine Sequenz oder irgendein anderes iterierbares Objekt mit Werten. Ausserdem ist Deine Schleife so geschrieben, dass die zweidimensionale Datenstruktur die von `fetchall()` kommt, in `visit` eindimensional wird. Bei einem Element pro Datensatz kein Problem aber zu umständlich, bei mehreren pro Datensatz ziemlich sicher nicht das Ergebnis das man haben möchte.

Bei der Namensgebung würde ich nicht abkürzen (`sqlite3` statt `lite`, `connection` statt `con`, …) und bei englisch bleiben. Denn mir ist nicht klar wie man `besuche` und `visit` auseinanderhalten soll, denn `visit` müsste vom Inhalt her eigentlich `visits` heissen und damit hätte man dann zwei Namen die im Grunde die gleiche Bedeutung haben. Ist irgendwie verwirrend.
Paulens
User
Beiträge: 5
Registriert: Freitag 3. März 2017, 00:10

BlackJack hat geschrieben:@Paulens: Ich denke Du versuchst da gerade ein Problem zu lösen das es gar nicht gibt. Du hast da bereits eine ganze Zahl, Datentyp `int`.

Und wie bekomme ich den dann in meine Liste eingelesen? :roll:

Und bei der Zeichenkette hast Du eventuell auch eine falsche Lösung. Die will man eigentlich als `unicode` haben. Zumindest innerhalb des Programms. Die nach ASCII zu wandeln mit allem was nicht ASCII ist als 'backslashreplace' kodiert, ist in der Regel nicht sinnvoll. Denn diese Ersetzung ist recht pythonspezifisch.

Hmm okay dann werd ich dies wohl auch nochmal verändern müssen.

Mir ist auch nicht ganz klar was Du mit der `visit`-Liste anfangen möchtest. Du musst ja mindestens noch so etwas wie eine ID in den Datensätzen haben, denn sonst kannst Du die erhöhten Werte hinterher nicht mehr den Besuchern zuordnen von denen die ursprünglichen Werte kamen. Oder vielleicht möchtest Du auch nur einen Wert von einem ganz bestimmten Besucher hochzählen. Dann macht es keinen Sinn die Zahlen für *alle* Besucher abzufragen.

Ja eigentlich brauche ich nur einen Wert der zu einem Besucher passt. :)
Das mit der zu Ordnung wollte ich dann dadurch lösen indem ich nach dem Namen von dem Besucher schaue und den Wert von der selben Stelle dann aus meiner visit Liste nehme.

Kann aber auch gut sein das ich hier einfach viel zu umständlich denke...
Ich möchte für einen bestimmten Besucher die Besuche hochzählen.



Was Du da mit ``+`` in der Schleife machst, ist ausserdem ziemlich ineffizient. ``+`` erstellt eine neue Liste aus den beiden Operanden. Da werden unnötig viele Listenobjekte als Zwischenergebnisse erstellt und die Daten immer und immer wieder im Speicher herumkopiert. Wenn man Werte an eine Liste anhängen möchte, nimmt man die `append()`-Methode für einzelne Werte oder `extend()` für eine Sequenz oder irgendein anderes iterierbares Objekt mit Werten. Ausserdem ist Deine Schleife so geschrieben, dass die zweidimensionale Datenstruktur die von `fetchall()` kommt, in `visit` eindimensional wird. Bei einem Element pro Datensatz kein Problem aber zu umständlich, bei mehreren pro Datensatz ziemlich sicher nicht das Ergebnis das man haben möchte.

Okay, dann werde ich das anders umsetzt. Das Plusrechnen bin ich noch von Java gewöhnt :)

Bei der Namensgebung würde ich nicht abkürzen (`sqlite3` statt `lite`, `connection` statt `con`, …) und bei englisch bleiben. Denn mir ist nicht klar wie man `besuche` und `visit` auseinanderhalten soll, denn `visit` müsste vom Inhalt her eigentlich `visits` heissen und damit hätte man dann zwei Namen die im Grunde die gleiche Bedeutung haben. Ist irgendwie verwirrend.

Da hast du vollkommen recht. Was ist der Grund das ich keine Abkürzungen für sqlite benutzen sollte?
Vielen Dank für dein ausführliches Feedback!!
BlackJack

@Paulens: Du musst Dir halt mal anschauen wie das Ergebnis von `fetchall()` aussieht, dann weisst Du auch was Du machen musst um die Zahlen in einer Liste zu haben.

Wo willst Du nach dem Namen schauen und was ist „die selbe Stelle“ in der Liste? Bei Deiner Datenbankabfrage ist keine bestimmte Reihenfolge der Ergebnisse garantiert, und selbst wenn dem so wäre, könnte sich die Datenbank zwischen zwei Abfragen verändert haben. Man braucht einen Primärschlüssel um Datensätze eindeutig identifizieren zu können. Üblicherweise führt man dafür einen künstlichen ein, selbst wenn beispielsweise der Besuchername eindeutig sein sollte. Denn spätestens bei Fremdschlüsselbeziehungen möchte man keine Zeichenketten als Primärschlüssel haben.

Wenn man den Wert für einen Besucher erhöhen möchte, dann fragt man den Datensatz für genau diesen Besucher ab, also mindestens ID und den Zählerwert, und aktualisiert dann den Zählerwert für die ID.

Wo benutzt man denn in Java das ``+``? Bei `List` beziehungsweise `Collection` geht es nicht, und bei Zeichenketten in einer Schleife haut einem normalerweise die IDE auf die Finger das das ineffizient ist und man einen `StringBuilder` verwenden sollte.

Abkürzungen die nicht allgemein anerkannt sind, machen den Code unverständlicher. Man muss bei `lite` erst einmal überlegen was das wohl bedeuten mag. Gegenfrage: Was bringt die Abkürzung? Ausser mehr Tipparbeit.
Paulens
User
Beiträge: 5
Registriert: Freitag 3. März 2017, 00:10

@BlackJack
BlackJack hat geschrieben:@Paulens: Du musst Dir halt mal anschauen wie das Ergebnis von `fetchall()` aussieht, dann weisst Du auch was Du machen musst um die Zahlen in einer Liste zu haben.

Das Ergebniss von 'fetchall()' für Besuche sieht wie folgt aus:
[(4,), (4,)]

Habe dann auch einen Wert der Liste verändern können die print ausgabe war dann folgende:
[(2,), 3]
Wenn ich die besuche dann wieder Update sind aber beide Einträge in der Datenbank 3 :K :K

Code: Alles auswählen

with con:
    cur = con.cursor()
    
    cur.execute("SELECT besuche FROM Besucher")

    besuche = cur.fetchall()
    besuche[1] = 3

    cur.execute("UPDATE Besucher SET besuche=?", str(besuche[1]))
    con.commit()
    

print besuche
Ich weiß das ich nur den einen Update, der andere verändert sich aber genau gleich wie besuche[1]
[/b]

Wo willst Du nach dem Namen schauen und was ist „die selbe Stelle“ in der Liste? Bei Deiner Datenbankabfrage ist keine bestimmte Reihenfolge der Ergebnisse garantiert, und selbst wenn dem so wäre, könnte sich die Datenbank zwischen zwei Abfragen verändert haben. Man braucht einen Primärschlüssel um Datensätze eindeutig identifizieren zu können. Üblicherweise führt man dafür einen künstlichen ein, selbst wenn beispielsweise der Besuchername eindeutig sein sollte. Denn spätestens bei Fremdschlüsselbeziehungen möchte man keine Zeichenketten als Primärschlüssel haben.

Ich möchte in meiner Datenbank nach dem Namen bzw. Primärschlüssel schauen.

Wenn man den Wert für einen Besucher erhöhen möchte, dann fragt man den Datensatz für genau diesen Besucher ab, also mindestens ID und den Zählerwert, und aktualisiert dann den Zählerwert für die ID.

Ja genau dies ist was ich tun möchte. Die Abfrage für einen bestimmten Benutzer habe ich schon. Jetzt fehlt nur noch das hochzählen für den Zählwert (besuche) vom Besucher.

Wo benutzt man denn in Java das ``+``? Bei `List` beziehungsweise `Collection` geht es nicht, und bei Zeichenketten in einer Schleife haut einem normalerweise die IDE auf die Finger das das ineffizient ist und man einen `StringBuilder` verwenden sollte.

Da haben wir wohl aneinander vorbei geredet ich hatte folgendes Szenario im Kopf:
[codebox=java file=Unbenannt.java]a= 1
a= a+1
print a[/code]


Abkürzungen die nicht allgemein anerkannt sind, machen den Code unverständlicher. Man muss bei `lite` erst einmal überlegen was das wohl bedeuten mag. Gegenfrage: Was bringt die Abkürzung? Ausser mehr Tipparbeit.

Okay, macht Sinn :) Hatte die Abkürzungen von einer Seite und dachte das diese allgemein anerkannt sind.
BlackJack

@Paulens: Hör besser auf Listen zu verändern und dann auch noch so, dass sie eine unregelmässige Datenstruktur enthalten.

Und natürlich sind nach dem UPDATE alle `besuche`-Werte 3, denn Du setzt da ja *alle* auf 3. Dazu wären auch die Zeilen 4 bis 7 völlig egal, denn die haben keinen Einfluss auf das Ergebnis. Was Du machst ist das hier:

Code: Alles auswählen

with con:
    cur = con.cursor()
    cur.execute('UPDATE Besucher SET besuche=?', 3)
    con.commit()
Wobei eigentlich machst Du etwas leicht anderes weil Du die 3 noch unsinnigerweise in eine Zeichenkette umwandelst. Lass da sein, das ist eine Zahl und soll ja wohl auch eine sein/bleiben.

Und wenn Du in der Datenbank nach dem Namen schauen willst, dann musst Du das halt auch machen. Also erst einmal Primärschlüssel und Besuchszähler für einen Namen ermitteln. Und nicht *alle* Zählerstände abfragen, auf eine Art und Weise die es unmöglich macht die Zähler wieder zuzuordnen.

Wenn Du schon die Abfrage für einen bestimmten Benutzer schon hast, warum ist die dann nicht in dem Code? Im gezeigten Code fragst Du die Zählerstände *aller* Benutzer ab.

Wenn Du den Zählstand nicht auch im Programm als Wert benötigst, kann man das hochzählen übrigens auch mit *einem* UPDATE in SQL erledigen.

Und das ``+`` oder ``+=`` würde man auch in Python zum addieren von Zahlen verwenden. Einen ``++``-Operator gibt es in Python allerdings nicht.
Paulens
User
Beiträge: 5
Registriert: Freitag 3. März 2017, 00:10

BlackJack hat geschrieben:@Paulens: Hör besser auf Listen zu verändern und dann auch noch so, dass sie eine unregelmässige Datenstruktur enthalten.

Das ist ja eigentlich auch nicht meine Absicht. Ich weiß nur leider nicht wie ich es anders machen kann :/

Und natürlich sind nach dem UPDATE alle `besuche`-Werte 3, denn Du setzt da ja *alle* auf 3. Dazu wären auch die Zeilen 4 bis 7 völlig egal, denn die haben keinen Einfluss auf das Ergebnis. Was Du machst ist das hier:

Code: Alles auswählen

with con:
    cur = con.cursor()
    cur.execute('UPDATE Besucher SET besuche=?', 3)
    con.commit()
Wobei eigentlich machst Du etwas leicht anderes weil Du die 3 noch unsinnigerweise in eine Zeichenkette umwandelst. Lass da sein, das ist eine Zahl und soll ja wohl auch eine sein/bleiben.

Okay hab mein Fehler da stand ich wohl auf dem Schlauch, wenn ich alle besuche in meiner Tabelle auf 3 setzte werden die natürlich auch auf 3 geändert.
Hab das ganze jetzt abgehändert und es funktioniert

Code: Alles auswählen

# -*- coding: utf-8 -*-
import sqlite3 as lite
import sys

con = lite.connect('testv2.db')

a = 1

with con:
    cur = con.cursor()
    cur.execute("SELECT mac FROM Besucher")
    mac = cur.fetchall()
    address = []
    for tup in mac:
        address = address + [item.encode('ascii', 'backslashreplace') for item in tup]
    
    
    cur.execute("SELECT besuche FROM Besucher")

    besuche = cur.fetchall()
    besuche[1] = 3
    besuche[0] = 7
    d = 'dani'
    cur.execute("UPDATE Besucher SET besuche=? WHERE mac=?", (str(besuche[0]), address[0]))
    con.commit()
    besuche[0] = besuche[0] +1

print besuche
print address[1]
print mac
(Die Besuche werden bewusst erst danach hochgezählt)
[/b]
Ist das eine Lösung die so praktikabel ist?
BlackJack

@Paulens: Eine Lösung wofür? Das ist alles ziemlicher Unsinn was da gemacht wird und Du scheinst irgendwie nichts zu berücksichtigen was man Dir sagt. Du setzt im Grunde `besuche` bei einem *zufälligen* `Besucher` auf den Wert '7' (was wohl eigentlich der Wert 7, also eine Zahl sein sollte). *Das* ginge mit deutlich weniger und auch weniger wirrem Code, aber es erscheint mir nicht wirklich sinnvoll das zu tun.
Paulens
User
Beiträge: 5
Registriert: Freitag 3. März 2017, 00:10

BlackJack hat geschrieben:@Paulens: Eine Lösung wofür?

Ohne unsinniges Listen verändern zum Ziel zu kommen

Das ist alles ziemlicher Unsinn was da gemacht wird und Du scheinst irgendwie nichts zu berücksichtigen was man Dir sagt. Du setzt im Grunde `besuche` bei einem *zufälligen* `Besucher` auf den Wert '7' (was wohl eigentlich der Wert 7, also eine Zahl sein sollte). *Das* ginge mit deutlich weniger und auch weniger wirrem Code, aber es erscheint mir nicht wirklich sinnvoll das zu tun.
Okay... ja da hast Du recht, hab irgendwie überlesen das ich davor ja noch die besuche auf einen entsprechenden Wert gesetzt habe so macht das keinen Sinn.

Meine Frage ist jetzt wie kann ich besuche[x] +1 rechnen und dann mit Update an die Datenbank senden?
Brauche ich noch eine zusätzliche Variable dafür? Bei dem folgenden Code bekomme ich (logischwerweise?) eine Fehlermeldung:

Code: Alles auswählen

# -*- coding: utf-8 -*-
import sqlite3 as lite
import sys

con = lite.connect('/var/www/html/testv2.db')


with con:
    cur = con.cursor()
    cur.execute("SELECT mac FROM Besucher")
    mac = cur.fetchall()
    address = []
    for tup in mac:
        address = address + [item.encode('ascii', 'backslashreplace') for item in tup]
    
    
    cur.execute("SELECT besuche FROM Besucher")

    besuche = cur.fetchall()

    besuche[0] = besuche[0] +1
 
    cur.execute("UPDATE Besucher SET besuche=? WHERE mac=?", (str(besuche[0]), address[0]))
    con.commit()
  

print besuche
Fehlermeldung: TypeError: can only concatenate tuple (not "int") to tuple

weitere Fragen:
1. Dachte ich das in [] eine Liste und keinen Tuple ist?!
2. Wie erhalte ich den Wert aus meiner Datenbank besuche als int?


Vielen Dank für deine tolle Unterstützung! :mrgreen: 8)
BlackJack

@Paulens: Es wird irgendwie nicht besser. Was Du machst um `address` zu erstellen ist immer noch ziemlich wirr. Und `address[0]` und `besuche[0]` müssen immer noch nicht zusammengehören. Die Reihenfolge der MAC-Adressen muss nicht mit der Reihenfolge der Besuchszähler übereinstimmen. Wenn Du das möchtest, dann musst Du sie in *einem* SELECT *gemeinsam* abfragen. Und wenn Du nur für die erste, zufällige MAC die Anzahl der Besuche erhöhen möchtest — wobei ich mich frage was das für einen Sinn machen soll — dann kannst Du das auch mit *einer* SQL-Anweisung machen. Dazu muss der Wert noch nicht einmal in Deinem Programm landen, weil man in SQL durchaus auch 1 addieren kann. Nur würde das keinen Sinn machen:
[codebox=postgresql file=Unbenannt.sql]UPDATE besucher
SET besuche=besuche+1
WHERE mac = (SELECT mac FROM besucher LIMIT 1)[/code]

Ad 1.: Ja das was da mit [] eingefasst dargestellt wird ist eine Liste. Und was sind das für Elemente *in* der Liste? Welchen Wert und Typ hat ``besuche[0]``? Kleiner Tipp, der Typ wird Dir von der Fehlermeldung schon verraten.

Ad 2.: In dem Du verstehst was `besuche` für eine Datenstruktur ist. Der Code sieht so aus als hättest Du das bei `mac` schon nicht wirklich verstanden, denn dann würde das da nicht so aberwitzig kompliziert aussehen.
Antworten