Datenbankabfrage mit Variablen

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MariaDB/MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
Antworten
Mahera
User
Beiträge: 9
Registriert: Montag 6. Januar 2020, 12:52

Hallo Zusammen,

ich programmiere seit kurzer Zeit Python und möchte über eine grafische Oberfläche eine SQL Abfrage machen.
Ich habe das ganze objektorientiert angelegt. Ich habe nun eine Combobox, welche Daten aus einem Datenframe, genauer die Werte einer Spalte enthält, die nicht gleich sind.
Nun möchte ich den ausgewählten Wert, den ich über ein Event (Änderung der Auswahl) bekomme in eine Abfrage einbinden, was aber immer wieder Fehlermeldungen generiert, dass die Abfrage nicht möglich ist.
hier kurz mein Code:
def search():
conn=sdfjlaskdjflasjdf <--- die verbindung funktioniert, da es geht, wenn question = 'select 3 from Table'
b=combo.get()
q = 'Column1, Column2 from Table WHERE Column2 in '+b
df = pd.read_sql_query(question=q, conn)
Würde mich freuen, wenn jemand eine Idee hätte.
Danke.
Sirius3
User
Beiträge: 17710
Registriert: Sonntag 21. Oktober 2012, 17:20

Hallo Mahera,

`read_sql_query` hat keinen Parameter `question`. Das SQL-Statement muß ein vollständiges SELECT -Statement enthalten. Man formatiert keine Parameter in SQL-Statements sondern benutzt Parameter und das `param`-Argument von ›read_sql_query‹.
Besser helfen könnte man, wenn Du hier funktionierenden Python-Code in Code-Tags </> posten würdest und auch die komplette dazu gehörige Fehlermeldung.
Mahera
User
Beiträge: 9
Registriert: Montag 6. Januar 2020, 12:52

Hallo,

sorry mein Fehler. habe die Funktion hier, nur die Verbindung zur Datenbank habe ich jetzt ausgeklammernt.

def query(question="select * from Robin_FlowCalibration"):
import pyodbc
conn = pyodbc.connect(***)
df_DUT = pd.read_sql_query(question, conn)
return df_DUT
Über die query Funktion rufe ich die Abfrage auf.

Jetzt will ich die Abfrage, also question wie Folgend zusamensetzen:
question = 'ProdDeviceId, TestRig from Robin_FlowCalibration WHERE TestRig in '+b
wobei b hier eine Variable ist, die ich aus einer Combobox via evnt abrufe und als String definiere.

Das hier ist de Fehlercode:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\PROGRA~1\Anaconda3\lib\site-packages\pandas\io\sql.py", line 1400, in execute
cur.execute(*args)
pyodbc.ProgrammingError: ('42000', "[42000] [Microsoft][ODBC SQL Server Driver][SQL Server]Incorrect syntax near ','. (102) (SQLExecDirectW)")

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "C:\PROGRA~1\Anaconda3\lib\tkinter\__init__.py", line 1705, in __call__
return self.func(*args)
File "C:/Users/e00204311/Desktop/PY/Fensteröffnen mit Button_200106_2.py", line 39, in search
data = Windowrules.query(question=q) <-- das ist das definierte Dataframe
File "C:/Users/e00204311/Desktop/PY/Fensteröffnen mit Button_200106_2.py", line 14, in query
df_DUT = pd.read_sql_query(question, conn) <-- das ist die abgefragte Tabelle als Dataframe
File "C:\PROGRA~1\Anaconda3\lib\site-packages\pandas\io\sql.py", line 314, in read_sql_query
parse_dates=parse_dates, chunksize=chunksize)
File "C:\PROGRA~1\Anaconda3\lib\site-packages\pandas\io\sql.py", line 1435, in read_query
cursor = self.execute(*args)
File "C:\PROGRA~1\Anaconda3\lib\site-packages\pandas\io\sql.py", line 1412, in execute
raise_with_traceback(ex)
File "C:\PROGRA~1\Anaconda3\lib\site-packages\pandas\compat\__init__.py", line 403, in raise_with_traceback
raise exc.with_traceback(traceback)
File "C:\PROGRA~1\Anaconda3\lib\site-packages\pandas\io\sql.py", line 1400, in execute
cur.execute(*args)
pandas.io.sql.DatabaseError: Execution failed on sql 'ProdDeviceId, TestRig from Robin_FlowCalibration WHERE TestRig in FCP-6.10': ('42000', "[42000] [Microsoft][ODBC SQL Server Driver][SQL Server]Incorrect syntax near ','. (102) (SQLExecDirectW)")
Benutzeravatar
__blackjack__
User
Beiträge: 13003
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Mahera: Wie Sirius3 schon schrieb formatiert man keine Werte in Zeichenketten mit SQL sondern benutzt Platzhalter im SQL und das `params`-Argument für die Werte. Und dann vielleicht auch besser gleich `read_sql_query()` statt `read_sql()` wie Sirius3 ja auch schon nahegelegt hat.

Soweit ich das sehe sind DB-API V2 `Connection`-Objekte auch nur bei `sqlite3` von Pandas wirklich unterstützt und für andere Datenbanken sollte man SQLAlchemy verwenden. Dann braucht man auch kein SQL mehr als Zeichenkette schreiben, sondern kann ein „selectable“ als `sql`-Argument übergeben. Was es einem speziell bei einem IN-Test einfacher macht wenn danach eine dynamische Anzahl von Werten folgen.

Importe sollten am Anfang vom Modul stehen, nicht in Funktionen versteckt.

Die Datenbankverbindung sollte genau wie Dateien explizit wieder geschlossen werden.
“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

Und wo ist jetzt die Zeile 39 von C:/Users/e00204311/Desktop/PY/Fensteröffnen mit Button_200106_2.py, bzw. die gesamte Datei?
Es ist eine schlechte Idee, Dateinamen mit Leerzeichen und Umlauten zu benutzen. Das läßt sich nämlich nicht als Modul importieren.

Wie es aussieht, gilt immer noch das selbe, was ich im ersten Beitrag schon geschrieben habe: Das SQL-Statement muß ein vollständiges SELECT -Statement enthalten. Man formatiert keine Parameter in SQL-Statements sondern benutzt Parameter und das `param`-Argument von ›read_sql_query‹.
Besser helfen könnte man, wenn Du hier funktionierenden Python-Code in Code-Tags </> posten würdest
Benutzeravatar
__blackjack__
User
Beiträge: 13003
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Hier mal ein Beispiel mit „reflection“ der Tabelle(n) (ungetestet):

Code: Alles auswählen

#!/usr/bin/env python3
import pandas as pd
from sqlalchemy import MetaData, create_engine, select


def main():
    engine = create_engine("mssql+pyodbc://<username>:<password>@<dsnname>")
    meta_data = MetaData(engine)
    meta_data.reflect()
    robin_flow_calibration_table = meta_data.tables["Robin_FlowCalibration"]

    values = ["a", "b", "c"]
    data = pd.read_sql_query(
        select(
            [
                robin_flow_calibration_table.c.ProdDeviceId,
                robin_flow_calibration_table.c.TestRig,
            ],
            robin_flow_calibration_table.c.TestRig.in_(values),
        ),
        engine,
    )
    print(data)


if __name__ == "__main__":
    main()
Ich würde aber eher die Tabellen im Code definieren und dabei gleich die Spalten so umbenennen, dass sie den Python-Namenskonventionen entsprechen.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Antworten