Werte escapen Datenbank

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MariaDB/MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
Antworten
köttbullar
User
Beiträge: 34
Registriert: Donnerstag 6. August 2015, 19:23

Hallo Python Forum,

ich habe ein kleines Problem und ich weiß auch woran es liegt, allerdings weiß ich nicht wie ich es behebe kann:-(
Und zwar will ich meine Datenbank befüllen. Was auch klappt, allerdings würde ich gerne in die Datenbank einen Wert schreiben und nicht die variable:
'result.bits[0]'
ich weiß wenn dann müsste es result.bits[0] so heißen ohne Die Anführungszeichen.
Leider funktioniert das auch nicht. Kann mir jemand sagen wie ich sowas escapen kann?

vielen Dank im voraus

hier mein Code:

Code: Alles auswählen

cur = conn.cursor()

cur.execute("INSERT INTO SPS (ID,State, SALARY) \
      VALUES (1, 'result.bits[0]', 65000.00 )")

cur.execute("INSERT INTO SPS (ID,State, SALARY) \
      VALUES (2, 'result.bits[1]', 65000.00)");

cur.execute("INSERT INTO SPS (ID,State, SALARY) \
      VALUES (3, 'result.bits[2]', 65000.00 )")


conn.commit()
print "Records created successfully";
conn.close()

BlackJack

@köttbullar: Dafür gibt es Platzhalter in SQL und den Datenbankmodulen in Python. Den oder die Platzhalter kommen in die SQL-Anweisung und eine Sequenz (Liste, Tupel, …) mit einem Wert pro Platzhalter wird als zweites Argument an `execute()` übergeben. Wenn Du mehr als einen Datensatz hast der verarbeitet werden soll, dann sollte man das nicht mit mehreren Anweisungen tun, sondern `executemany()` verwenden. Das erwartet statt einem, mehrere Werte nach dem oben beschriebenen Format. Das sieht dann beispielsweise so aus:

Code: Alles auswählen

    cursor.executemany(
        'INSERT INTO SPS (ID, State, SALARY) VALUES (1, ?, 65000.00)',
        ((bit,) for bit in result.bits)
    )
Ob das '?' für das Datenbankmodul das Du verwendest der richtige Platzhalter ist, musst Du ausprobieren/in der Dokumentation vom Modul nachlesen.

Das verschiedene Module unterschiedliche Platzhalter verwenden ist einer der Gründe warum ich eigentlich grundsätzlich mit SQLAlchemy als Abstraktionsschicht dazwischen packe.
köttbullar
User
Beiträge: 34
Registriert: Donnerstag 6. August 2015, 19:23

Hallo Black Jack,

ich will es Schritt für Schritt angehen,
Deshalb ohne den executemany

ich hab den Code wie folgt angepasst:

Code: Alles auswählen

a = 'ABC'
cur.execute("INSERT INTO SPS (ID,State, SALARY) \
      VALUES (1, ?, 65000.00 )a");
ich dachte ich weise der variable a den Wert ABC zu
danach übergebe ich dem Platzhalter ? die Variable a

Leider kommt dann folgende Fehlermeldung:
VALUES (1, ?, 65000.00 )a");
psycopg2.ProgrammingError: syntax error at or near ","
LINE 1: ...ERT INTO SPS (ID,State, SALARY) VALUES (1, ?, 65000.00...


wie macht man das richtig?

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

@köttbullar: irgendwo ein a in einen String zu setzen, macht ja keinen Sinn. Du solltest nochmal ganz an den Anfang gehen und lernen, was Strings sind, und was Variablen sind. Dann hat Dir BlackJack schon gesagt, dass es vom Datenbankmodul abhängt, welchen Platzhalter man braucht, und dass man das am besten in der Dokumentation zum Modul nachliest.
BlackJack

@köttbullar: Vielleicht mal als Anreiz wie so etwas mit SQLAlchemy aussehen kann:

Code: Alles auswählen

    state = 'ABC'

    # 
    # Variante 1:
    # 
    # Mit SQLAlchemy's ORM (eine passende `Sps`-Klasse vorausgesetzt):
    # 
    session.add(Sps(id=1, state=state, salary=65000.0))
    session.commit()

    # 
    # Variante 2a:
    # 
    # Mit der SQLAlchemy Kern-API (ein passendes `sps_table`-Object
    # vorausgestzt):
    # 
    connection.execute(
        sps_table.insert().values(id=1, state=state, salary=65000.0)
    )

    # 
    # Variante 2b:
    # 
    # Falls man kein „autocommit“ möchte muss man bei der Kern-API für eine
    # Transaktion sorgen (die ORM-API verwendet intern automatisch
    # Transaktionen):
    # 
    with connection.begin():
        connection.execute(
            sps_table.insert().values(id=1, state=state, salary=65000.0)
        )

    # 
    # Variante 2c:
    # 
    # Falls das Tabellenobject die das Datenbank-`Engine`-Objekt kennt, zum
    # Beispiel weil man das der Tabelle/den Tabellenmetadaten bekannt gemacht
    # hat, oder weil das Tabellenobject durch „reflection“ zustande kam und
    # daher ”weiss” wie es die DB erreichen kann aus deren Schema es erstellt
    # wurde, kann man auch direkt auf dem `Insert`-Objekt `execute()` aufrufen.
    # (Hier mit „autocommit“)
    # 
    sps_table.insert().values(id=1, state=state, salary=65000.0).execute()
Eine `Sps`-Klasse für die ORM-API wird man sich in der Regel selber schreiben. Bei der Kern-API kann man sich `Table`-Exemplare erstellen in dem man entweder die Schema-Definition manuell angibt, bei den meisten DBMS kann man aber auch ”reflection” verwenden, also die DB fragen wie denn die Tabelle aussieht und ein entsprechendes Objekt erstellen lassen. Das kann man für einzelne Tabellen machen, man kann aber auch beim `Metadata`-Objekt sagen man möchte gerne alle Tabellen abfragen und als Abbildung bekommen. Da kann man die Tabellen aber auch wieder einschränken wenn man nicht tatsächlich *alle* haben möchte sondern nur die Untermenge die man benötigt.

Da die Spaltennamen in dem Beispiel so unpythonisch aussehen was die Schreibweise angeht, würde ich diese Tabelle in jedem Fall manuell definieren und die Namen wie im Quelltext oben an die Python-Gepflogenheiten anpassen.

Generell ist Gross-/Kleinschreibung bei Namen in SQL keine so gute Idee. Es gibt DBMS die beachten das und welche die tun das nicht. Der SQL-Standard sieht „case insensitive“ für Namen vor. Da können dann unter Umständen zwei verschiedene Sichtweisen in Code und in der Datenbank aufeinander treffen. Deshalb verwende ich in der Regel nur Kleinbuchstaben für SQL-Namen.
köttbullar
User
Beiträge: 34
Registriert: Donnerstag 6. August 2015, 19:23

ich bekomm mach irgendwie was falsch trotz tutorial
Kann mir jemand sagen wie ich ABC in die Datenbank bekomme?

vielen Dank

Code: Alles auswählen


state = 'ABC'
cur.execute("INSERT INTO SPS (ID,state, SALARY) \
      VALUES (1, state=state, 65000.00)");
BlackJack

@köttbullar: Sirius3 hat doch die entsprechende Stelle in der Dokumentation von dem Modul verlinkt, welches Du verwendest. Da sind *Beispiele*. Was ist denn da jetzt noch unklar? An der Stelle wo der Wert stehen soll muss ein *Platzhalter* hin. Und der Wert selbst muss als *zweites Argument* an `execute()` *übergeben* werden. Und zwar nicht direkt der Wert sondern eine Sequenz (Liste, Tupel, …) mit einem Wert pro Platzhalter. Wenn im SQL nur ein Platzhalter steht, dann halt eine Sequenz mit nur dem einen Wert. Irgendwie habe ich ein Deja Vu. ;-)

Also: Hast Du Platzhalter in dem SQL? Nein! Übergibst Du ein zweites Argument? Nein!
köttbullar
User
Beiträge: 34
Registriert: Donnerstag 6. August 2015, 19:23

ok, jetzt habe ich ein Platzhalter und ein 2.tes Argument eingefügt.
Allerdings kommt nun ein Syntx Fehler:

state = 'ABC'
cur.execute("INSERT INTO SPS (ID,State, SALARY) \
VALUES (1, '%s', 65000.00(state))");

Code: Alles auswählen

state = 'ABC'
cur.execute("INSERT INTO SPS (ID,State, SALARY) \
      VALUES (1, '%s', 65000.00(state))");
köttbullar
User
Beiträge: 34
Registriert: Donnerstag 6. August 2015, 19:23

neues Beispiel:

Code: Alles auswählen

variableA = "A"
variableB = "B"


cur.execute('insert into SPS (ID,State) values("%s", "%s")' % \
             (variableA, variableB))
Nach meiner Erklärung habe ich nun 2 Platzhalter. In diesen Platzhalter füge ich nun folgende Variablen ein:
VariableA = A und VariableB = B
theoretisch müsste ich nun in meiner Datenbank A und B stehen haben
BlackJack

@köttbullar: Die Anführungszeichen um die Platzhalter gehören da nicht hin. Und ohne `commit()`-Aufruf landet das nicht in der Datenbank.
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@köttbullar: Du solltest immer den Fehler inklusive Traceback hier posten. Sollen wir raten, wo und welcher Fehler bei Dir auftaucht? Programmieren ist nicht Raten! Man muß schon verstehen, was man da schreibt. Die Beispiele in der Dokumentation sind doch relative deutlich. Schau man genau nach, wo sie sich von Deinem Geschriebenen unterscheiden.
köttbullar
User
Beiträge: 34
Registriert: Donnerstag 6. August 2015, 19:23

Hallo nochmals,

ja das mit den Anführungszeichen war mein Fehler weil ich einfach schon vieles versucht habe
der commit habe ich einfach vergessen mitzukopieren.
hier also nochmals der komplette code

Code: Alles auswählen

variableA = "A"
variableB = "B"


cur.execute('insert into SPS (ID,State) values(%s, %s)' % \
             (variableA, variableB))

conn.commit()
und hier die Fehlermeldung:
Traceback (most recent call last):
File "./test1.py", line 51, in <module>
(variableA, variableB))
psycopg2.ProgrammingError: column "a" does not exist
LINE 1: insert into SPS (ID,State) values(A, B)

warum sagt er dass die column "a" nicht existiert?
natürlich existiert diese nicht ich habe ja die Dapalte ID und State
er sol ja den Wert a in die Tabelle schreiben!!!
Benutzeravatar
/me
User
Beiträge: 3554
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

Du solltest ja auch keine Stringformatierung verwenden sondern execute die Aufgabe der passenden Parameterersetzung überlassen.

Code: Alles auswählen

cur.execute('insert into SPS (ID, State) values(%s, %s)', (variableA, variableB))
Antworten