cx_Oracle: Daten per executemany an Tabelle anfügen

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MariaDB/MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
Antworten
chrischn
User
Beiträge: 18
Registriert: Freitag 23. September 2016, 09:35

Hallo, ich versuche mehrere Datensätze per Oracle an eine Tabelle anzufügen, verzweifle jedoch gerade.

Testtabelle anlegen :

CREATE TABLE person (

name VARCHAR(40),
birthday VARCHAR(40),
PRIMARY KEY (name)
);


Code: Alles auswählen

#! python3

import cx_Oracle
con = cx_Oracle.connect('user/pass@mydb/TEST')
print(con.version)

cursor = con.cursor()

# Beispieldaten
dictionary = [{'1':'Hans','2':'TESTEST'},{'1':'Frank','2':'TESTTEST2'}]

insert = "insert into person(name, birthday) values (:1, :2)"
cursor.prepare(insert)
cursor.executemany(None, dictionary)
cursor.commit()
cursor.close()

Als Fehler erhalte ich :

cx_Oracle.DatabaseError: ORA-01036: Variablenname/-nummer ungültig

Ich teste nun schon einige Zeit herum und habe schon mehrere Dinge versucht.
Ist das Dictionary nicht korrekt ?


Das Einfügen von einzelnen Daten funktioniert :

Code: Alles auswählen

name = 'Horst2'
birthday = 'Blaba'

insert = "insert into person(name, birthday) values (:name, :birthday)"
cursor.execute(insert, {'name': name, 'birthday': birthday})

con.commit()
con.close()
Oracle Version 11
cx_oracle
Zuletzt geändert von chrischn am Donnerstag 3. November 2016, 13:21, insgesamt 1-mal geändert.
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@chrischn: warum machst Du es nicht so, wie bei Einzeln-INSERTs?

Code: Alles auswählen

dictionary = [{'name':'Hans','birthday':'TESTEST'},{'name':'Frank','birthday':'TESTTEST2'}]
insert = "insert into person(name, birthday) values (:name, :birthday)"
cursor.executemany(insert, dictionary)
PS: Ein birthday-Feld sollte vom Typ Datum sein.
BlackJack

@chrischn: :1 und :2 sind was anderes als :name und :birthday. Das eine sind Zahlen die als Index in eine Sequenz verwendet werden (:1 ist dabei das erste Element, also am Index 0!), das andere Namen die als Schlüssel für ein Wörterbuch verwendet werden. Also entweder machst Du das was Sirius vorgeschlagen hat, oder Du übergibst eine Sequenz von Sequenzen für die Datensätze.

Wobei der Name `dictionary` in jedem Fall falsch wäre.

Edit: Auch noch was zum Datenbankentwurf: Name ist kein guter Primärschlüssel. Es soll Leute geben die den gleichen Namen haben. War gerade gestern in der Firma ein Thema weil zwei Kunden den gleichen Vor- und Nachnamen haben. Und der war nicht einmal *so* verbreitet wie Peter Müller oder so etwas.
chrischn
User
Beiträge: 18
Registriert: Freitag 23. September 2016, 09:35

Funktioniert :)

Zwischendurch hatte ich es glaube ich auch schon mal, hatte nur nicht verstanden, dass die Fehlermeldung

"Unique Constraint (UNITRADE.SYS_C00157555) verletzt"

eine Schlüsselverletzung ist, da der Datensatz schon vorhanden war und hab immer gedacht, dass grundsätzlich
was nicht passt.

Besten Dank für die Hilfe

In vielen Beispielen wurde mit dem Befehl "cursor.prepare" gearbeitet ?

Gruß
Chrischn
chrischn
User
Beiträge: 18
Registriert: Freitag 23. September 2016, 09:35

@Blackjack

vielen Dank für die Infos. Habe die Abfragen heute zum ersten mal erstellt und mir fehlt da noch ein
wenig Erfahrung :-)

Ich werde es dann mit den Sequenzen versuchen, denke ich.

Gruß
Chrischn
BlackJack

@chrischn: `prepare()` ist keine Methode die Bestandteil der DB API 2.0 für Cursor-Objekte ist. Das ist also eine Erweiterung von `cx_Oracle`. Würde ich deshalb nicht verwenden wenn es keinen guten Grund dafür gibt.

Andererseits würde ich ohne guten Grund die DB API 2.0 nicht verwenden, weil die gerade bei den Platzhaltern nicht wirklich sinnvoll von verschiedenen Datenbanken abstrahiert. Dafür gibt es dann SQLAlchemy. Was zudem auch noch ein ORM bietet.
Antworten