INSERT INTO Statement erstellen

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.
Antworten
JigSaw
User
Beiträge: 12
Registriert: Donnerstag 16. Dezember 2021, 10:45

Hallo zusammen,

ich muss INSERT INTOs erstellen, um Daten in eine Datenbank zu schreiben. Die Daten erhalte ich in einer CSV Datei.
Mein Problem dabei ist es, dass in manchen Feldern ein string steht, dort aber auch NULL drin stehen kann.

So komme ich mit der f-String Formatierung nicht weiter, da wenn ich

f"INSERT INTO table_name (column1, column2, column3) VALUES ({value1}, '{value4}', '{value3}')"

ausgebe, schreibt er die NULL natürlich als String wegen den Anführungszeichen.

Natürlich könnte ich vorher eine if-Abfrage machen, ob dieser Wert NULL ist und dann einfach

f"INSERT INTO table_name (column1, column2, column3) VALUES ({value1}, NULL, '{value3}')"

benutzen, die Tabelle hat allerdings 26 Spalten, in denen sowohl strings, als auch NULL vorkommt und daher wäre es ein ziemliches durcheinander alle Kombinationen abzudecken.

Mit sqllite kann ich leider nicht arbeiten, da ich nicht direkt in die Datenbank schreiben kann, sondern es über INSERT INTO Statements machen muss.

Hat jemand eine Idee wie ich das am besten löse? Gibt es vielleicht Module dafür?
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Du löst das, indem du den wirklich grundlegendsten Tipp aller Zeiten im Umgang mit SQL beherzigst: man baut keine SQL statements aus Eingaben zusammen. Sondern verwendet Platzhalter, und Argumente. Und dann sorgt die Datenbank selbst, bzw. der Treiber, dafür, dass None au NULL wird. Und strings in der DB landen.

Dieses Thema wird hier quasi permanent diskutiert. Lies mal ein bisschen durchs Forum.
JigSaw
User
Beiträge: 12
Registriert: Donnerstag 16. Dezember 2021, 10:45

Es sind keine Eingaben die ich dort versuche einzuspielen, daher ist die Gefahr einer SQL-Injection durch Benutzereingaben nicht da. Ich brauche eine Textfile mit ca. 40.000 INSERT INTO Statements die ich aus einer CSV Datei generieren muss, ich kann nicht direkt in die Datenbank mit einem Modul schreiben.

Ich weiß dass man es normalerweise mit z.B. sqllite machen kann und dort dann einfach mit

cursor.execute("INSERT INTO xxx (column1, column2 , column3 ) VALUES (?,?,?)",(value1, value2, value3),)

arbeiten kann. Das habe ich aber nur im zusammenhang mit execute gefunden, das kann ich aber nicht benutzen.

Ich habe es jetzt mit replace gelöst.
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Das könntest du schon benutzen, besser wäre aber natürlich executemany zu nutzen. Wie das funktioniert, wie auch alle anderen bisher angesprochenen Punkte werden übrigens schon am Anfang der sqlite3 Modul Dokumentation erwähnt. Da findest du auch Beispiele.
Sirius3
User
Beiträge: 17710
Registriert: Sonntag 21. Oktober 2012, 17:20

@JigSaw: nein es geht nicht in erster Linie um SQL-Injections, jedenfalls keine absichtlichen, sondern um ganz Normale Strings, die halt eine spezielle Bedeutung haben können, also z.B auch ', das ja schon irgendwo in den Daten vorkommen könnte.
Deshalb mußt Du in Deinem Fall jeden Wert ordentlich transformieren, am besten, indem Du Dir eine Funktion schreibst, wo Du genau all diese Fälle abfangen kannst.

Code: Alles auswählen

def sql_escape(value):
    if value is None:
        return "NULL"
    elif isinstance(value, str):
        return "'{}'".format(value.replace("'", "''"))
    elif isinstance(value, int):
        return str(int)
    else:
        raise TypeError()

sql = f"INSERT INTO table_name (column1, column2, column3) VALUES ({sql_escape(value1)}, {sql_escape(value4)}, {sql_escape(value3)})"
JigSaw
User
Beiträge: 12
Registriert: Donnerstag 16. Dezember 2021, 10:45

@DasIch: Es geht nicht darum, dass das Module nicht Möglichkeiten dafür bietet. Es geht darum, dass ich diese Daten in eine Datenbank einspielen muss, die auf einem Rechner läuft auf dem ich kein Python installieren darf. Es ist nur SSMS installiert. Die builtin Funktion von SSMS zum einspielen von Daten per CSV Dateien bringt einen zum verzweifeln, daher die umständliche, unsaubere Lösung.

@Sirius3: Vielen Dank, das hat mir weiter geholfen!
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Du hast glaube ich ein grosses Missverstaendnis, was sqlite ist, und was nicht. sqlite ist eine eigene Datenbank, file-basiert. Nicht ein universeller Weg, mit irgendeiner Datenbank zu reden. Keine Ahnung was SSMS sein soll - MS SqlServer? Auch dafuer gibt es DB-Adapter, womit die hier von diversen Leuten vorgetragenen Moeglichkeiten von execute und Parametern durchaus zum tragen kommen. https://docs.microsoft.com/en-us/sql/co ... rver-ver15
JigSaw
User
Beiträge: 12
Registriert: Donnerstag 16. Dezember 2021, 10:45

Das mit sqllite habe ich anscheinend wirklich falsch verstanden. Nichtsdestotrotz ist es mir nicht möglich mit Python eine Datenbankverbindung aufzubauen, da auf dem Rechner kein Python installiert ist und es auch nicht installiert werden kann/darf. Daher bringt mir der Python SQL Driver nichts, trotzdem danke für die Hinweise. Mit SSMS meine ich SQL Server Management Studio.
Sirius3
User
Beiträge: 17710
Registriert: Sonntag 21. Oktober 2012, 17:20

Auf einem Datenbank-Rechner arbeitet man eh nicht direkt, sondern verbindet sich per Netzwerkschnittstelle, und da gibt es auch was für Python.
SQL Server Management Studio ist zum Konfigurieren der Datenbank gedacht, nicht in erster Linie, dass man damit Daten einspielt.
JigSaw
User
Beiträge: 12
Registriert: Donnerstag 16. Dezember 2021, 10:45

@Sirius3: Leider ist es ein Kundenrechner auf den ich nur Zugriff per TeamViewer habe, ich kann dort nichts installieren und Schnittstellen gibt es dort keine, daher ist mir keine andere Idee als diese eingefallen.
Antworten