Seite 1 von 1

Probleme mit INSERT INTO

Verfasst: Montag 2. November 2009, 15:28
von SteeWeeDee
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)?

Verfasst: Montag 2. November 2009, 15:39
von Pekh
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".

Verfasst: Montag 2. November 2009, 15:53
von SteeWeeDee
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))

Verfasst: Montag 2. November 2009, 16:56
von Pekh
ja.

Verfasst: Montag 2. November 2009, 18:57
von SteeWeeDee
Funktioniert leider nicht. Die Fehlermeldung sagt syntax error near %. Eine Idee?

Verfasst: Montag 2. November 2009, 19:15
von Pekh
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.

Verfasst: Montag 2. November 2009, 19:39
von pillmuncher
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.

Verfasst: Montag 2. November 2009, 19:48
von Pekh
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.

Verfasst: Montag 2. November 2009, 19:52
von SteeWeeDee
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.

Verfasst: Montag 2. November 2009, 19:59
von Pekh
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.

Verfasst: Montag 2. November 2009, 20:34
von SteeWeeDee
Ja, verständlich. Muss ich mir halt was anderes einfallen lassen :( Eine Abfrage in Python und dann mit einfachem Insert arbeiten.

Verfasst: Montag 2. November 2009, 23:19
von ms4py
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.

Verfasst: Dienstag 3. November 2009, 00:46
von pillmuncher
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.

Verfasst: Dienstag 3. November 2009, 00:55
von ms4py
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

Verfasst: Dienstag 3. November 2009, 15:42
von SteeWeeDee
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?

Verfasst: Dienstag 3. November 2009, 15:47
von Hyperion
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?

Verfasst: Mittwoch 4. November 2009, 00:04
von SteeWeeDee
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?

Verfasst: Mittwoch 4. November 2009, 08:16
von frabron
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.

Verfasst: Mittwoch 4. November 2009, 11:22
von ms4py
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.