Probleme mit INSERT INTO

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MariaDB/MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
Antworten
SteeWeeDee
User
Beiträge: 34
Registriert: Donnerstag 18. September 2008, 14:10

Hallo!

Meine Frage bezieht sich auf Insert Statements. In einigen Büchern (z.B. jenes von Galileo Computing) sthet, dass es möglich ist, in Insert´s Where Bedingungen anzuhängen.

In meinem Programm sollen Länder in eine Tabelle eingefügt werden. Die Tabelle Angreifer besteht aus den Spalten ip (IP Adressen) und land (Länder-Code aus denen die Adressen stammen z.B. DE,AT) . Wird ein Land gefunden, soll es dort eingefügt werden, wo die IP Adresse in der Tabelle übereinstimmt. Die Tabelle ist bereits mit allen IP Adressen gefüllt und alle land Einträge sind "None".

Beispiel. für die IP Adresse A wurde das Land B gefunden. Nun soll das Land B in der Tabelle Angreifer in genau der Zeile eingefügt werden, wo die IP Adresse A schon vorhanden ist. Das habe ich so gelöst:

Code: Alles auswählen

cursor.execute("""INSERT INTO Angreifer(land) VALUES(country) WHERE "Angreifer.ip = gefundene_Landes_IP" """)
Aber ich erhalte bei WHERE einen Syntax Error. Ich verwende SQLite3.
Sind Where Bedingungen hier nicht möglich? Wenn ja, wie könnte das Problem sonst gelöst werden? Habe mir schon ein paar Gedanken zu Alternativen gemacht und folgendes Prinzip erdacht:

Land gefunden (das geschieht in Python) => finde die Zeile in der gilt:"IP Adresse für das gefundene Land = Eintrag in Spalte ip" => Zeilennummer auslesen (über Zeilenindex? mit Schlüssel?) => in Spalte mit dem gefundenen Index das Land in Spalte land einfügen.

Geht es auch einfacher? Wie kann ich denn den Spaltenindex(sprich die Nummer) auslesen und, falls es bisher funktioniert, brauche ich anschließend nicht wieder eine WHERE Bedingung (füge dort Land ein wo Zeilenindex.ip = IP)?
Pekh
User
Beiträge: 482
Registriert: Donnerstag 22. Mai 2008, 09:09

Von einem INSERT ... WHERE habe ich noch nie etwas gehört. Mag sein, daß ein sehr spezifischer SQL-Dialekt so etwas unterstützt, aber Standard ist das nicht. Um Felder in bereits bestehenden Datensätzen zu bearbeiten verwendet man "UPDATE tabelle SET key=value WHERE".
SteeWeeDee
User
Beiträge: 34
Registriert: Donnerstag 18. September 2008, 14:10

Vielleicht habe ich mich auch nur verlesen *schäm*

Also in etwa so?

Code: Alles auswählen

cursor.execute("""UPDATE Angreifer SET land = %s WHERE Angreifer.ip = %s """, (country, IP des LAndes))
Pekh
User
Beiträge: 482
Registriert: Donnerstag 22. Mai 2008, 09:09

ja.
SteeWeeDee
User
Beiträge: 34
Registriert: Donnerstag 18. September 2008, 14:10

Funktioniert leider nicht. Die Fehlermeldung sagt syntax error near %. Eine Idee?
Pekh
User
Beiträge: 482
Registriert: Donnerstag 22. Mai 2008, 09:09

Du sagtest, du verwendest sqlite3 ? Dann sollte es funktionieren. Wobei ich jetzt nicht weiß, ob die dreifachen Anführungszeichen an der Stelle nicht vielleicht stören. Ansonsten würde ich vermuten, daß du irgendwo im Umkreis der Zeile einen Fehler hast.
Benutzeravatar
pillmuncher
User
Beiträge: 1484
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

SteeWeeDee hat geschrieben:

Code: Alles auswählen

cursor.execute("""UPDATE Angreifer SET land = %s WHERE Angreifer.ip = %s """, (country, IP des LAndes))
Ich vermute IP-Adresse und Land liegen als Strings vor. Dann musst du sie wahrscheinlich in Gänsefüßchen setzen:

Code: Alles auswählen

cursor.execute('UPDATE Angreifer SET land = "%s" WHERE Angreifer.ip = "%s"', (country, IP des LAndes))
Oder Hochkommata.


Was anderes: Hab ich dich richtig verstanden, dass du mehrere Ländercodes komma-getrennt hintereinander in dasselbe Feld schreiben willst? Also zB.

Code: Alles auswählen

... set land = "de,at,it" ...
Gruß,
Mick.
In specifications, Murphy's Law supersedes Ohm's.
Pekh
User
Beiträge: 482
Registriert: Donnerstag 22. Mai 2008, 09:09

Nein, ich Hochkommata muß er sie nicht setzen, darum kümmert sich die DBAPI bzw das entsprechende Datenbankmodul. Das ist ja das Schöne an dieser %s - Notation, die nichts mit der Stringformatierung zu tun hat. Der Fehler muß woanders liegen.
SteeWeeDee
User
Beiträge: 34
Registriert: Donnerstag 18. September 2008, 14:10

Habe vorher mit Typedefs schon dafür gesorgt, dass sie sicherlich in String Form vorliegt.

Code: Alles auswählen

cursor.execute("UPDATE Angreifer SET land = country WHERE Angreifer.ip = IP des Landes")
Hier sagt er mir es besteht ein Syntax Fehler near WHERE.

Nein, die Länder liegen nicht als csv vor.
Pekh
User
Beiträge: 482
Registriert: Donnerstag 22. Mai 2008, 09:09

Das ist klar. Country ist an dieser Stelle sicherlich der String 'country', und den mußt du dann schon in Anführungszeichen setzen. Wenn du aber irgendwo eine Variable 'country' hast, und deren Inhalt an dieser Stelle einsetzen willst, solltest du die '%s' - Notation verwenden, wie du es Anfangs ja auch getan hast.
SteeWeeDee
User
Beiträge: 34
Registriert: Donnerstag 18. September 2008, 14:10

Ja, verständlich. Muss ich mir halt was anderes einfallen lassen :( Eine Abfrage in Python und dann mit einfachem Insert arbeiten.
ms4py
User
Beiträge: 1178
Registriert: Montag 19. Januar 2009, 09:37

Bei sqlite sind die Platzhalter einer parameterisierten Abfrage nicht ``%s`` sondern ``?``
http://docs.python.org/dev/library/sqli ... or.execute

Das sieht dann so aus:

Code: Alles auswählen

cursor.execute("""UPDATE Angreifer SET land=? WHERE Angreifer.ip=? """, (country, country_ip))
Oder manchmal auch besser so:

Code: Alles auswählen

cursor.execute("""UPDATE Angreifer SET land=:country WHERE Angreifer.ip=:ip """, {'country': country, 'ip': country_ip})
@pillmuncher: Man sollte SQL-Abfragen nie über die normale String-Formatierung generieren. Über die parameterisierte Abfrage wird die SQL-Syntax automatisch an den jeweiligen Datentyp angepasst (nur so funktioniert z.B. auch die Konvertierung zw. datetime.datetime und TIMESTAMP) und man kann damit SQL-Injections verhindern.
Benutzeravatar
pillmuncher
User
Beiträge: 1484
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

ice2k3 hat geschrieben:@pillmuncher: Man sollte SQL-Abfragen nie über die normale String-Formatierung generieren. Über die parameterisierte Abfrage wird die SQL-Syntax automatisch an den jeweiligen Datentyp angepasst (nur so funktioniert z.B. auch die Konvertierung zw. datetime.datetime und TIMESTAMP) und man kann damit SQL-Injections verhindern.
Da hast du wohl recht. Das letzte Mal, als ich richtig viel mit SQL gearbeitet habe, waren noch 2-Tier-Client-Server-Architekturen en vogue, und SQL-Injections waren unbekannt, und Betriebs-Systeme kamen noch ohne Web-Browser daher. :shock: Jetzt weißt du ungefähr, wie alt ich bin :)

Gruß,
Mick.
In specifications, Murphy's Law supersedes Ohm's.
ms4py
User
Beiträge: 1178
Registriert: Montag 19. Januar 2009, 09:37

pillmuncher hat geschrieben:
ice2k3 hat geschrieben:@pillmuncher: Man sollte SQL-Abfragen nie über die normale String-Formatierung generieren. Über die parameterisierte Abfrage wird die SQL-Syntax automatisch an den jeweiligen Datentyp angepasst (nur so funktioniert z.B. auch die Konvertierung zw. datetime.datetime und TIMESTAMP) und man kann damit SQL-Injections verhindern.
Da hast du wohl recht. Das letzte Mal, als ich richtig viel mit SQL gearbeitet habe, waren noch 2-Tier-Client-Server-Architekturen en vogue, und SQL-Injections waren unbekannt, und Betriebs-Systeme kamen noch ohne Web-Browser daher. :shock: Jetzt weißt du ungefähr, wie alt ich bin :)
Nicht genau, dafür bin ich zu jung :P
SteeWeeDee
User
Beiträge: 34
Registriert: Donnerstag 18. September 2008, 14:10

Habe das alte Backup mit der nicht funktionierenden Update Methode wieder hervorgekramt (habe ja schon eine Alternative entwickelt) und mit ? läufts. Danke :)

Noch eine Frage am Rande, dass mir bei meiner Alternativentwicklung untergekommen ist: Wie verhindere ich dass zwei identische Datensätze in der Tabelle sind? Soll wohl irgendwie mit dem Parameter UNIQUE bei CREATE TABLE funktionieren. Kann ich damit nur eine Spalte absichern oder wie funktioniert das genau?

Hier ein Beispiel mit einer Tabelle mit zwei Spalten die ich konsistent halten will, also soll keine Zeile zwei Mal darin vorkommen:

CREATE TABLE test (
a INT NOT NULL ,
b INT NOT NULL ,
UNIQUE (a AND b))

So in etwa?
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Da es sich bei unique um ein column-constraint handelt, kann man es nur jeweils auf ein Attribut anwenden. Du müßtest also sowohl be a als auch bei b separat angeben.

http://www.sqlite.org/lang_createtable.html

Du weißt aber schon, was e in Schlüssel ist, oder?
SteeWeeDee
User
Beiträge: 34
Registriert: Donnerstag 18. September 2008, 14:10

Mist! :(
Ich bräuchte etwas, das verhindert, dass eine Zeile doppelt in der Tabelle vorkommt. Mit RowID kann ich das wohl auch nicht machen. Unique heißt ja nur, dass ein Inhalt einer Reihe nicht doppelt vorkommen darf. Verstehe ich das richtig?
Das ist aber, z.B. bei mehreren IP´s aus dem gleichem Land, in der Landspalte gegeben. Es sollte nur eine gesamte Zeile nicht doppelt vorkommen.
Du weißt aber schon, was e in Schlüssel ist, oder?
Welches e meinst du?
frabron
User
Beiträge: 306
Registriert: Dienstag 31. März 2009, 14:36

Ein UNIQUE Constraint auf einer Spalte bezieht sich natürlich immer auf den Inhalt der Spalte und nicht der Reihe ... wie kommst du denn da drauf? Für solche Fragen sei mal das Handbuch empfohlen ;)
Da steht dann auch beim Link von Hyperion, dass man einen unique tableconstraint anlegen kann, der mehrere Spalten zusammengefassen kann
mehreren IP´s aus dem gleichem Land, in der Landspalte gegeben
Sowas ist natürlich schlechtes Design, besser wäre es eine Tabelle mit IPs zu haben und die über eine 1:n Beziehung mit der Landestabelle zu verknüpfen.
ms4py
User
Beiträge: 1178
Registriert: Montag 19. Januar 2009, 09:37

frabron hat geschrieben:
mehreren IP´s aus dem gleichem Land, in der Landspalte gegeben
Sowas ist natürlich schlechtes Design, besser wäre es eine Tabelle mit IPs zu haben und die über eine 1:n Beziehung mit der Landestabelle zu verknüpfen.
Ganz genau! Unter dem Stichwort "Normalisierung von Datenbanken" findest du das noch ausführlicher beschrieben.
Antworten