Anfänger: Hilfe mit python bzw. psycopg2

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
truehumandesign
User
Beiträge: 20
Registriert: Sonntag 4. Dezember 2011, 19:20

Hoi!

Als meinen ersten Beitrag habe ich gleich mal eine Frage.
Dies hier ist mein Code:

Code: Alles auswählen

amnr = raw_input("AMNR eingeben:")
amnrgen = ('UPDATE tmp_foo SET "AMNR" = '+ amnr +'//||("LFDNR");')

cur.execute(amnrgen, amnr)
Der Funktioniert auch sehr gut, ausser wenn ich meinen hier, fettmarkierten, Slash einfügen will.
Die AMNR soll einfach von einem Slash zur LFDN nur getrennt sein 0000/2222
Gibt es eine möglichkeit direkt den Slash beim raw_input mit anzugeben? "Ohne ihn händisch tippen zu müssen"

Python Version 2.7.2

Dank und Gruß!
Zuletzt geändert von truehumandesign am Sonntag 4. Dezember 2011, 22:46, insgesamt 1-mal geändert.
BlackJack

@truehumandesign: Du vermischt da einiges. Erst einmal kannst Du den Schrägstrich natürlich an die Zeichenkette anfügen die Du eingelesen hast bevor Du den Wert an die Datenbank übergibst. Aber *das* solltest Du nicht tun in dem Du die SQL-Anweisung als Zeichenkette mit den Werten zusammen bastelst, sondern mit einer parametrisierten Abfrage. Also mit Platzhaltern im SQL. Und die Werte werden dann als Tupel (oder allgemein als Sequenz) als zweites Argument bei `execute()` übergeben.
truehumandesign
User
Beiträge: 20
Registriert: Sonntag 4. Dezember 2011, 19:20

Hi!
Vielleicht kannst du mir das noch irgendwie genauer definieren (vllt. sogar mit Codebeispiel)
Hab leider noch nicht so den durchblick in Python

Vielen Dank!
BlackJack

@truehumandesign: Hast Du das Tutorial aus der Python-Dokumentation schon durchgearbeitet? Da gibt es Beispiele was man mit Zeichenketten so anstellen kann.

Wie man Parameter bei `execute()` übergibt steht in der `psycopg`-Dokumentation. Auch mit Beispielen.
truehumandesign
User
Beiträge: 20
Registriert: Sonntag 4. Dezember 2011, 19:20

@BlackJack
Ich verstehe was du meinst. In der psycopg doku steht folgendes drin
Warning Never, never, NEVER use Python string concatenation (+) or string parameters interpolation (%) to pass variables to a SQL query string. Not even at gunpoint
The correct way to pass variables in a SQL command is using the second argument of the execute() method:

>>> SQL = "INSERT INTO authors (name) VALUES (%s);" # Note: no quotes
>>> data = ("O'Reilly", )
>>> cur.execute(SQL, data) # Note: no % operator
jedoch übergibt er die data nur wenn ein fixer datensatz drinsteht

wenn ich jedoch den Wert meiner Eingabe da drin stehen haben will geht das ganze leider nicht
So schaut das ganze jetzt aus

Code: Alles auswählen

amnrgen = ("""UPDATE tmp_foo SET "AMNR" = %s||("LFDNR");""")
amnr = raw_input('AMNR eingeben:',)
cur.execute(amnrgen, amnr)

Code: Alles auswählen

    cur.execute(amnrgen, amnr)
TypeError: not all arguments converted during string formatting
BlackJack

@truehumandesign: Da ist ein Unterschied zwischen der Dokumentation und dem was Du machst. Schau mal genau welcher Datentyp in der Dokumentation übergeben wird und dann was Du stattdessen übergibst.
truehumandesign
User
Beiträge: 20
Registriert: Sonntag 4. Dezember 2011, 19:20

jup ich habs bemerkt und jetzt komplett anders gelöst

Code: Alles auswählen

cur.execute('UPDATE tmp_foo SET "AMNR" = %s%s||("LFDNR")', (raw_input('AMNR Eingeben:'),'/' ))
mehr ist es schon nicht mehr und es funktioniert!!!!
Das Einzigste was mir noch nicht passt ist, dass er ein Hochkomma vor dem Slash setzt
Die Ausgabe in die Tabelle sieht folgendermaßen aus 12345'/00001
Stimmt da noch was nicht mit meinem Syntax?
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

truehumandesign hat geschrieben:Die Ausgabe in die Tabelle sieht folgendermaßen aus 12345'/00001
Stimmt da noch was nicht mit meinem Syntax?
In der Tat. Du gibst zwei Werte hintereinander an, so dass im Endeffekt der String

Code: Alles auswählen

'12345''/00001'
in der Datenbank ankommt. Die beiden Anführungszeichen am Anfang und Ende kennzeichnen für die Datenbank Beginn und Ende des Strings. Das doppelte Anführungszeichen in der MItte wird von der Datenbank als Escaping interpretiert und zu einem Anführungszeichen eingedampft. Du musst also, wenn du nur einen Wert hast, auch nur einen Wert ins SQL-Statement schreiben.

Wenn ich es richtig verstanden habe soll der Wert aus der Eingabe mit dem Wert der laufenden Nummer verkettet werden und das getrennt mit einem Slash. Ich zeige das mal an einem Beispiel auf und verwende nach der Empfehlung aus PEP-8 Bezeichnernamen in Kleinbuchstaben.

Code: Alles auswählen

new_value = amnr + '/' + str(lfdnr)

# oder alternativ
new_value = '{0}/{1}'.format(amnr, lfdnr)
Aus deinem Programm wird damit

Code: Alles auswählen

amnr = raw_input('AMNR eingeben:',)
new_value = '{0}/{1}'.format(amnr, lfdnr)
cur.execute('UPDATE tmp_foo SET amnr = %s', new_value)
Edit: Warum die letzte Codezeile nicht ganz richtig ist und noch ein wenig bearbeitet werden muss kann man unter Passing parameters to SQL queries nachlesen. Danke an BlackJack, der mich darauf aufmerksam gemacht hat - und auch schon in seinem ersten Post zu diesem Thema darauf hingewiesen hat. :oops:
Zuletzt geändert von /me am Montag 5. Dezember 2011, 08:28, insgesamt 2-mal geändert.
BlackJack

@/me: Psst, jetzt hast Du bei der Übergabe an `execute()` den gleichen Fehler gemacht wie am Anfang truehumandesign. :-P
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

BlackJack hat geschrieben:@/me: Psst, jetzt hast Du bei der Übergabe an `execute()` den gleichen Fehler gemacht wie am Anfang truehumandesign. :-P
Ja, habe ich. Aufgrund der Tatsache, dass ich in letzter Zeit häufig ORMs verwende, war mir die Syntax nicht mehr geläufig und ich habe den Fehler gemacht sie von oben zu übernehmen, statt nachzuschauen.
truehumandesign
User
Beiträge: 20
Registriert: Sonntag 4. Dezember 2011, 19:20

Habs jetzt so zusammengeschrieben:

cur.execute('UPDATE tmp_foo SET "AMNR" = %s||("LFDNR");', '{0}/'.format(raw_input('AMNR Eingeben:')), )

Macht er trotzdem nicht
cur.execute('UPDATE tmp_foo SET "AMNR" = %s||("LFDNR");', '{0}/'.format(raw_input('AMNR Eingeben:')), )
TypeError: not all arguments converted during string formatting
Der spinnt jetzt womöglich wegen der '' bei dem format rum. Kann ich das umgehen?

EDIT: hat sich erledigt.. sieht jetzt folgendermaßen aus:
cur.execute("""UPDATE tmp_foo SET "AMNR" = %s||("LFDNR");""", ('{0}/'.format(raw_input('AMNR Eingeben:')), ))
Danke!
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Und ist immer noch falsch. Sagmal ließt du die Posts hier?
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
truehumandesign
User
Beiträge: 20
Registriert: Sonntag 4. Dezember 2011, 19:20

ja ich lese die posts..
bitte erleuchte mich und sag mir was daran falsch ist.

Laut psycopg doc. solls folgendermaßen aussehen

Code: Alles auswählen

amnrgen = 'UPDATE tmp_foo SET "AMNR" = %s||("LFDNR");'
amnr = '{0}/'.format(raw_input('AMNR Eingeben:'))
cur.execute(amnrgen, amnr)
da bringt er mir aber die ganze zeit ne fehlermeldung
cur.execute(amnrgen, amnr)
TypeError: not all arguments converted during string formatting
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

truehumandesign hat geschrieben:

Code: Alles auswählen

cur.execute(amnrgen, amnr)
cur.execute(amnrgen, amnr)
TypeError: not all arguments converted during string formatting
Laut Dokumentation muss als zweiter Parameter eine Liste oder ein Tupel (genauer gesagt etwas iterierbares) angegeben werden.

Mir ist allerdings noch nicht wirklich klar geworden, woher das LFDNR kommt. Ursprünglich dachte ich, es solle eine von außen übergebene Variable sein. Inzwischen neige ich ja zu der Ansicht, dass das der Wert eines Felds des Datensatzes ist der einfach noch mal an den restlichen Text im Feld AMNR angehängt werden soll. Was davon ist denn korrekt?
Benutzeravatar
sparrow
User
Beiträge: 4193
Registriert: Freitag 17. April 2009, 10:28

@truehumandesign kannst du mal bitte zeigen wie genau der SQL-Befehl aussehen soll der am Ende ausgeführt werden soll?
Und vor allem: was er bewirken soll?

Das würde uns sehr helfen dir zu helfen.
truehumandesign
User
Beiträge: 20
Registriert: Sonntag 4. Dezember 2011, 19:20

Hi.. ihr habt recht das hätte ich vielleicht dazu schreiben sollen.

Die SQL Query sieht folgendermaßen aus:

Code: Alles auswählen

UPDATE tmp_foo SET "AMNR" = '12345678/'||("LFDNR")
die LFDNR ist ein Feld mit 8 Zahlen in der Datenbank
Davor soll eine Nummer mit einem Slash kommen
"123456/12345678"
Jedoch will ich über das python script, dass die Zahl vor dem Slash als Eingabefeld möglich ist, da sich diese Nummer ändern kann.

Vielleicht wird es jetzt etwas deutlicher.

Vielen Dank und Gruß!
frabron
User
Beiträge: 306
Registriert: Dienstag 31. März 2009, 14:36

Ich würde AMNR und LFDNR nicht in einem Feld gemeinsam speichern, sondern getrennt lassen. Das macht nur unnötige Arbeit beim Konsistent halten der DB, wenn du in einem Feld nicht normalisierte Daten vorhälst (siehe Normalisierung). Gerade weil du auch schreibst:
Jedoch will ich über das python script, dass die Zahl vor dem Slash als Eingabefeld möglich ist, da sich diese Nummer ändern kann
Das Zusammensetzen würde ich dann im Client (Python-Skript) oder im Select machen ...

Code: Alles auswählen

select AMNR||'\\'||LFDNR AS bar from foo
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

truehumandesign hat geschrieben:

Code: Alles auswählen

UPDATE tmp_foo SET "AMNR" = '12345678/'||("LFDNR")
die LFDNR ist ein Feld mit 8 Zahlen in der Datenbank
OK. jetzt sollten wir erst einmal das Statement aufräumen. Du hast da meiner Meinung nach mehrere unnötige Anführungszeichen und Klammern verteilt.

Code: Alles auswählen

UPDATE tmp_foo SET AMNR = '12345678/' || LFDNR
Als flexiblen Teil benötigst du also das '12345678/'. Das wird also im Python-Code der Teil, der den Platzhalter bekommt.

Code: Alles auswählen

UPDATE tmp_foo SET AMNR = %s || LFDNR
Der Wert, der an %s übergeben wird besteht aus einem eingegebenen Wert und einem folgenden Slash.

Code: Alles auswählen

value= '{0}/'.format(eingabewert)
Jetzt muss man nur noch das Statement ausführen. Wichtig ist, dass die zu ersetzenden Werte in einem Statement nicht als einzelne Parameter, sondern in einer Liste oder einem Tupel angegeben werden.

Code: Alles auswählen

cur.excute('UPDATE tmp_foo SET AMNR = %s || LFDNR', (value, ))
So weit zum technischen. Logisch habe ich allerdings ein Problem mit dem Konstrukt. Du baust dir da eine nicht erforderliche Redundanz ein. Oder soll die LFDNR als Teil des Felds AMNR nur ein Default-Wert sein der später überschrieben werden kann?
truehumandesign
User
Beiträge: 20
Registriert: Sonntag 4. Dezember 2011, 19:20

Die zusammengeführte Nummer (AMNR) wird auf einer Druckmaschine angedruckt die den Wert aus der SQL Datenbank ausliest
d.h. es gibt für mich keine Möglichkeit die zwei nummern getrennt zu lassen.
OK. jetzt sollten wir erst einmal das Statement aufräumen. Du hast da meiner Meinung nach mehrere unnötige Anführungszeichen und Klammern verteilt.

Code: Alles auswählen

UPDATE tmp_foo SET AMNR = '12345678/' || LFDNR
Das kann ich nicht, weil Postgre sonst amnr statts AMNR verwendet (Der Feldname ist in Großbuchstaben)

Edit:

@/me
Hat super funktioniert!!
im Programm steht nun

Code: Alles auswählen

amnr = '{0}/'.format(raw_input('AMNR Eingeben:'))
cur.execute('UPDATE tmp_foo SET "AMNR" = %s ||("LFDNR")', (amnr, ))
Jedoch versteh ich nicht warum ich dieses hier nicht verwenden soll.

Code: Alles auswählen

"""UPDATE tmp_foo SET "AMNR" = %s||("LFDNR");""", ('{0}/'.format(raw_input('AMNR Eingeben:')), ))
Das Ergebniss ist ja das gleiche
frabron
User
Beiträge: 306
Registriert: Dienstag 31. März 2009, 14:36

Die Druckmaschine führt SQL auf euer DB aus? Ansonsten hab ich dir doch gezeigt, wie man das auch im Statement zusammenführen kann bei der Abfrage ...
Antworten