Datum als Wert in SQL-Statement funktioniert nicht

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MariaDB/MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
Antworten
artesi
User
Beiträge: 5
Registriert: Freitag 18. Mai 2007, 09:04

Hallo zusammen,

ich habe folgendes Problem: Eigentlich bin ich mit meiner Anwendung so gut wie fertig, ich habe eine Datenbankanwendung mit PyQt4 programmiert, die auf eine PostgreSQL Datenbank zugreift und von Kontinent über Land zu den dortigen Messstationen für Klimadatenmessungen navigiert.
Nachdem man dann in einem zweiten Formular, Messreihe, Anfangs- und Enddatum ausgewählt hat anhand von Combo Boxen werden diese Werte über Signale übergeben und in Klassenvariablen gespeichert.
Jetzt möchte ich in der letzten Methode die Klassenvariablen übernehmen und die Werte über Platzhalter meinem SQL Befehl übergeben, hierfür habe ich folgeneden Code:

Code: Alles auswählen

def getExport(self):
        
        export = []
        station = self.stationList 
        von = DateTime.strptime(self.vonDate, 'DD.MM.YYYY')
        bis = self.bisDate
        row = self.row
        
        liste = []     ## Stringliste für Platzhalter in SQL-Befehl für endgültigen Export
        for i in station:
            if i[0] == None:
                continue
            else:
                liste.append("m."+i[0])

        values = ", ".join(liste)

        self.cur.execute("SELECT m.datum, m.zeit, %s FROM sicht m, reihe r WHERE r.intervall like '%s' AND m.datum BETWEEN '%s' AND '%s';" % (values, row, von, bis))
        ex = self.cur.fetchall()

        print ex
        return ex
Wie zu sehen, habe ich schon das mx Modul versucht einzusetzen, aber ich bekomme einen Attribute Error, der besagt, die Funktion strptime() sei nicht bekannt..
Den normalen String als Wertübergabe akzeptiert pgdb (ich arbeite mit der pyGreSQL Schnittstelle) nicht und es gibt einen DB-Error ähnlich "cannot handle <class PyQt4.QtCore.QString instance at ...>, andere QString Werte hat die Anwendung jedoch als Wertübergabe für SQL-Befehle immer akzeptiert, dh. am QString kanns nicht liegen (das habe ich geprüft!). Ich denke, PostgreSQL hat Probleme das Datum im Statement abzugleichen und braucht einen richtig formatierten Wert. Wieso Python jetzt die Funktion nicht erkennt wundert mich, ich habe sie importiert!

Bin sehr dankbar, wenn mir jemand weiterhelfen kann,

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

artesi hat geschrieben:die Werte über Platzhalter meinem SQL Befehl übergeben
Hallo Marion!

Willkommen im Python-Forum!

Ich bin heute schon müde. Deshalb die Kurze Antwort.

Verwende NICHT die %s-Syntax von Python für solche Dinge, sondern verwende die in die DB-API eingebaute Ersetzung dafür. Dann funktioniert es auch mit dem Datum.

Code: Alles auswählen

import datetime
cur.execute(
    """
    INSERT INTO test (
      von_datum, bis_datum
    )
    VALUES (
      ?, ?
    )
    """,
    (datetime.datetime(2006, 1, 1), datetime.datetime.now())
)
mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
artesi
User
Beiträge: 5
Registriert: Freitag 18. Mai 2007, 09:04

Hallo Gerold,

Danke dir :-)

Und danke auch für die schnelle Antwort trotz Müdigkeit.

Aber das wird wohl zur Lösung meines Problems nicht beitragen, da ich nichts in die Datenbank schreiben muss, sondern nur anhand eines zuvor übergeben QStrings, der in einer Klassenvariablen gespeichert ist und zu gegebener Zeit in die entsprechende Methode "geholt" wird, einen SELECT auf die DB ausführen möchte, der mir alles Messwerte innerhalb der übergebenen Zeitspanne (vonDate, bisDate) ausgibt.
Die Daten sind in der Datenbank im Datentyp date gespeichert und haben das Format DD.MM.YYY.
Nun dachte ich, dass er den String nicht abgleichen kann, weil

1. Die Tabelle einen date Datentyp erwartet und
2. der übergebene String sowieso die Form YYYY-MM-DD hat (das ergibt sich so beim Auslesen aus der DB, wenn automatisch aus dem Datum ein String generiert wird)

Und nun ist es tatsächlich so, dass die Anwendung wohl ein Problem mit dem QString an der Stelle hat, da sie sich bei jeglichem Versuch, etwas mit dem Wert anzufangen (sei es ein print auszuführen, oder ein str(QString)) aufhängt und auf den Speicher verweist ... "der Befehl read könne auf dem Speicher nicht ausgeführt werden"...

Ich weiß wirklich nicht woran das liegt, weil in der Methode zuvor, als der Wert aus der Combobox übergeben und in der Klassenvariablen self.vonDate zugewiesen wird, das print noch funktioniert...
(ich sollte mal vielleicht die Python Stringumwandlung dort versuchen... :-) )

Trotzdem danke für deine Antwort, bei Neuigkeiten, oder falls ich das Problem in den Griff bekomme, werde ich mich melden, ansonsten bin ich natürlich über jeden weiteren Tip oder Denkanstoß glücklich... :-)

Grüße,
Marion.
Y0Gi
User
Beiträge: 1454
Registriert: Freitag 22. September 2006, 23:05
Wohnort: ja

Die von gerold aufgezeigte und in der DB-API 2.0 spezifizierte Nutzung von Platzhaltern (die übrigens je nach Adapter unterschiedlich sein können, also mal '%s', mal '?', mal noch was anderes) funktioniert natürlich bei allen Statement-Arten, auch SELECTs. Durch das implizite Autoescaping lassen sich damit schon mal gewollte oder ungewollte SQL-Injections unterbinden (Grüße an PHP :P) - ist allerdings nicht überall sinnvoll, etwa beim Tabellennamen.

Kann es sein, dass du dein DateTime-Objekt mit `strftime` in einen passenden String umwandeln willst? Das gibt es laut der Doku nämlich im Gegensatz zu `strptime`.
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Hallo artesi!

Code: Alles auswählen

import datetime

sql = \
    """
    SELECT 
      m.datum, m.zeit, %(felder)s 
    FROM 
      sicht m, reihe r 
    WHERE 
      (r.intervall like '%(intervall)s') AND 
      (m.datum BETWEEN ? AND ?)"
    """ % dict(
        felder = "vorname, nachname, wasweisich",
        intervall = "daily"
    )

# Wandle dein Datum in ein richtiges datetime.datetime-Objekt um
von = datetime.datetime(2006, 10, 1)
bis = datetime.datetime(2007, 1, 31)
cur.execute(sql, (von, bis))
mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

@gerold, Y0Gi: Warum erklärt ihr das hier, wenn wir dazu eine ausführliche Wiki Seite haben? Im Grunde stört mich das weniger, aber ist doch immer mit Zeitaufwand verbunden.

[wiki]Parametrisierte SQL-Queries[/wiki]

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

jens hat geschrieben:Warum erklärt ihr das hier, wenn wir dazu eine ausführliche Wiki Seite haben?
Hallo Jens!

Ich krieg immer Augenschmerzen, wenn ich das Wiki ansehe. Ich weiß nicht, wer auf die Idee gekommen ist dieses Grün zu verwenden... :lol:
Mehr als ich bis jetzt für das Wiki gemacht habe könnt ihr auch in Zukunft nicht von mir erwarten.

lg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Y0Gi
User
Beiträge: 1454
Registriert: Freitag 22. September 2006, 23:05
Wohnort: ja

jens hat geschrieben:@gerold, Y0Gi: Warum erklärt ihr das hier, wenn wir dazu eine ausführliche Wiki Seite haben? Im Grunde stört mich das weniger, aber ist doch immer mit Zeitaufwand verbunden.

[wiki]Parametrisierte SQL-Queries[/wiki]
Mal davon abgesehen, dass ich a) nicht die Themen des Wikis im Kopf habe und b) der Code der genannten Seite nicht der tollste ist (abwechselnd einfache und doppelte Hochkommata als String-Delimiter, SQL ohne Uppercase-Keywords, zu lange Zeilen), erklärt ein Blick in die DB-API 2.0 nicht nur parameterisierte Queries dem nicht komplett unerfahrenen und Englisch-ungelehrten Python-Programmierer ausreichend gut, sondern liefert auch gleich viel anderes Wissenswertes mit, das man möglichst kennen sollte.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Wie immer heißt es, nicht meckern, sondern verbessern ;) Das Wiki ist dazu da, das jeder sich einbringen kann ;)

Ich denke das der Wiki Artikel in dem Punkt doch um einiges einfacher zu verstehen ist, als die DB-API 2.0... :lol:

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Y0Gi
User
Beiträge: 1454
Registriert: Freitag 22. September 2006, 23:05
Wohnort: ja

jens hat geschrieben:Wie immer heißt es, nicht meckern, sondern verbessern ;) Das Wiki ist dazu da, das jeder sich einbringen kann ;)
Der Spruch taucht hier auch fast zu oft auf. Ich frage mich persönlich das eine oder andere Mal, warum ich mir Arbeit an einem Dokument machen soll, das woanders sauberer und vollständiger bereits existiert.
jens hat geschrieben:Ich denke das der Wiki Artikel in dem Punkt doch um einiges einfacher zu verstehen ist, als die DB-API 2.0... :lol:
Was es da zu Lachen gibt, entzieht sich mir gerade. Wie gesagt, die Präsentation ist in meinen Augen schon bedenklich. Da wundert es mich nicht, dass gerold lieber direkt ein - angepasstes - Beispiel bringt.

*Wenn* da jetzt sinnvollerweise stehen würde, welcher DB-Adapter welche Placeholder-Syntax nutzt, *dann* wäre da ja zumindest ein gewisser praktischer Informationsgehalt. So fehlt da aber IMHO der Bezug als auch der Mehrwert des Wikis gegenüber der Spec, um den Wiki-Artikel vorzuziehen.


Wiki hin oder her, es reicht nicht, zu dem einen oder anderen Thema schnell ein bisschen Code hinzufriemeln. Solange das keine runde Sache ist, brauchen solche Artikel hier nicht verlinkt werden. Bei Wikipedia würde sowas wohl schnell der Löschung verfallen.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Leonidas hat den Wiki Artikel übrigens gerade angepasst ;)... Eigentlich wollte ich das gerade machen :lol:

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Y0Gi hat geschrieben:
jens hat geschrieben:Wie immer heißt es, nicht meckern, sondern verbessern ;) Das Wiki ist dazu da, das jeder sich einbringen kann ;)
Der Spruch taucht hier auch fast zu oft auf. Ich frage mich persönlich das eine oder andere Mal, warum ich mir Arbeit an einem Dokument machen soll, das woanders sauberer und vollständiger bereits existiert.
Weil der Artikel im Wiki für einstiger besser geeignet ist als ihnen die gesammte Spezifikation vorzuwerfen. Dann wird er auch eher gelesen, noch dazu wenn er auf Deutsch ist. Im Forum habt ihr beide (Gerold und du) ja nicht nur einen Link zur DB-API 2.0 hingeworfen sondern auch noch ein paar Worte dazu geschrieben. Hast du die HTTP-Spezifikation durchgelesen, bevor du den Browser zum ersten Mal verwendet hast? Deswegen gibt es Einführungsdokumente, die den Leser den einstieg erleichtern. Dadurch wird er ja nicht abgehalten, die Spezifikation zu lesen.
Y0Gi hat geschrieben:*Wenn* da jetzt sinnvollerweise stehen würde, welcher DB-Adapter welche Placeholder-Syntax nutzt, *dann* wäre da ja zumindest ein gewisser praktischer Informationsgehalt. So fehlt da aber IMHO der Bezug als auch der Mehrwert des Wikis gegenüber der Spec, um den Wiki-Artikel vorzuziehen.
Klar, sowas könnte man zwar machen, aber ich sehe den Sinn einer solchen auflistung nicht ganz. Man könnte zwar hinschreiben, dass psycopg2 und psycopg1 ``pyformat`` nutzen, aber dass findet der Nutzer mit ``paramstyle`` auch selbst heraus. Was der Nutzer aber, besonders wenn er Anfänger ist
Y0Gi hat geschrieben:Wiki hin oder her, es reicht nicht, zu dem einen oder anderen Thema schnell ein bisschen Code hinzufriemeln. Solange das keine runde Sache ist, brauchen solche Artikel hier nicht verlinkt werden. Bei Wikipedia würde sowas wohl schnell der Löschung verfallen.
Da hast du recht. Ich habe jetzt einige von dir angesprochene Dinge in dem Artikel geändert und die DB-API 2.0 verlinkt. Aber ich denke es ist dennoch gut die Informationen auf deutsch da zu haben. Man sollte natürlich noch den Text über SQL-Injections erweitern, damit sich die Leser etwas darunter vorstellen können auch wenn sie damit noch nicht gearbeitet haben.
Wenn man von der Seite argumentiert, dass die Originalinformation besser und vollständiger ist, dann kann man die deutsche Mailingliste und Newsgroup ebenso wie das Forum abschaffen und ebenso auch die deutschsprachigen Python-Bücher. Aber viele Leute fanden die in der Vergangenheit trotz ihrer Imperfektheit schon hilftreich also ist es möglich, dass sie anderen Leuten auch in Zukunft noch nützlich sein werden.

Also falls du noch Vorschläge zu dem Artikel hast, können wir gerne noch Details besprechen und versuchen ihn so nützlich wie möglich zu machen.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
artesi
User
Beiträge: 5
Registriert: Freitag 18. Mai 2007, 09:04

Hallo alle zusammen, die ihr Tips gegeben habt :-)

Ich muss ich wirklich für eure Mühen nochmals bedanken....
Melde mich jetzt erst so spät, weil ich das Thema beiseite legen musste, um an meiner Diplomarbeit weiter schriftlich zu arbeiten. Heute hatte ich mich dem Thema noch einmal gewidmet und es mit dem time Modul versucht. Und so hat es nach ewigen Versuchen geklappt. Das war einfach ein Problem kombiniert aus QStrings (Werte aus übergabe von Comboboxen!!! ich arbeite mit PyQt4) und das Einbinden von vier Parametern in ein SQL SELECT aus Klassenvariablen, die im Vorfeld durch die Comboboxen ausgewählt wurden... etwas kompliziert... aber am Ende hats jetzt geklappt und ich will nur kurz mit meinem Code, der jetzt funktioniert allen denen zeigen, wie die Lösung hierzu ausehen kann, falls es jemanden mal interessieren sollte... :-)

Code: Alles auswählen

vonDate = None
    bisDate = None
    row = None

def getExport(self):
        ## Variablen bestimmen:
        export = []
        station = self.stationList 
        print type(station), station
        
        liste = []     ## Stringliste für Platzhalter in SQL-Befehl für endgültigen Export
        for i in station:
            if i[0] == None:
                continue
            else:
                liste.append("m."+i[0])

        values = ", ".join(liste)
        print "values: ", values
        
        row = self.row
        print "Typ 'row': ", type(row) 

        von = self.vonDate
        bis = self.bisDate
        print "Typ Von aus Klasse: ", type(von), "Wert 'Von': ", von
        print "Typ Bis aus Klasse: ", type(bis), "Wert 'Bis': ", bis
        
        v_tup = time.strptime(von, "%Y-%m-%d")
        v_str = time.strftime("%d.%m.%Y", v_tup)
        print type(v_str),  v_str
        
        b_tup = time.strptime(bis, "%Y-%m-%d")
        b_str = time.strftime("%d.%m.%Y", b_tup)
        print type(b_str),  b_str
        
        print "ich versuche,  mal sehen..."
        self.cur.execute("SELECT m.datum, m.zeit, %s FROM sicht m, reihe r WHERE r.intervall = '%s' AND m.datum BETWEEN '%s' AND '%s';" % (values, row, v_str, b_str))
       
        ex = self.cur.fetchall()
        return ex
An weiterer Stelle wird die ex liste dann in eine CSV Datei geschrieben. Mein Programm ist fertig...
Ich hatte wirklich viele, wenn nicht fast alle Versionen zur Parameterübergabe ausprobiert und als ich kaum noch an einen Lösungsweg geglaubt hatte, hats auf einmal hiermit funktioniert... und im Prinzip ist es genau die Version, die ich auch am Anfang hatte, es waren eben wirklich die QStrings, die nicht akzeptiert wurden und das Datumsformat... das hab ich dann geändert und jetzt funktioniert es prima :-)

Ich wünsche allen noch ein schönes Restwochenende und ich werd mal weiterschreiben ;-)

Marion.
Antworten