Oracle

Unterstützung für die Oracle Database Datenbank.

Die folgende Tabelle fasst die aktuellen Support-Level für Datenbank-Release-Versionen zusammen.

Unterstützte Oracle Database Versionen

Support-Typ

Versionen

Supported version

11+

Best effort

9+

DBAPI Unterstützung

Die folgenden Dialekt-/DBAPI-Optionen sind verfügbar. Bitte beachten Sie die einzelnen DBAPI-Abschnitte für Verbindungsinformationen.

Auto Increment Verhalten

SQLAlchemy Table-Objekte, die Integer-Primärschlüssel enthalten, werden normalerweise als "autoincrementing" angenommen, d.h. sie können ihre eigenen Primärschlüsselwerte bei einem INSERT generieren. Für die Verwendung in der Oracle Database stehen zwei Optionen zur Verfügung: die Verwendung von IDENTITY-Spalten (nur Oracle Database 12 und höher) oder die Zuordnung einer SEQUENCE zur Spalte.

Angabe von GENERATED AS IDENTITY (Oracle Database 12 und höher)

Ab Version 12 kann Oracle Database Identitätsspalten mit Hilfe von Identity verwenden, um das autoincrementing Verhalten anzugeben.

t = Table(
    "mytable",
    metadata,
    Column("id", Integer, Identity(start=3), primary_key=True),
    Column(...),
    ...,
)

Die CREATE TABLE für das obige Table-Objekt wäre

CREATE TABLE mytable (
    id INTEGER GENERATED BY DEFAULT AS IDENTITY (START WITH 3),
    ...,
    PRIMARY KEY (id)
)

Das Identity Objekt unterstützt viele Optionen zur Steuerung des "autoincrementing" Verhaltens der Spalte, wie z.B. den Startwert, den Inkrementwert usw. Zusätzlich zu den Standardoptionen unterstützt Oracle Database das Setzen von Identity.always auf None, um den generierten Standardmodus zu verwenden und GENERATED AS IDENTITY in der DDL darzustellen. Es unterstützt auch das Setzen von Identity.on_null auf True, um ON NULL in Verbindung mit einer 'BY DEFAULT' Identitätsspalte anzugeben.

Verwendung einer SEQUENCE (alle Oracle Database Versionen)

Ältere Versionen von Oracle Database hatten keine "autoincrement"-Funktion: SQLAlchemy setzt auf Sequenzen, um diese Werte zu erzeugen. Bei älteren Oracle Database Versionen *muss immer explizit eine Sequenz angegeben werden, um Autoincrement zu aktivieren*. Dies weicht von den meisten Dokumentationsbeispielen ab, die die Verwendung einer datenbankfähigen Datenbank annehmen. Um Sequenzen anzugeben, verwenden Sie das Objekt sqlalchemy.schema.Sequence, das einem Column-Konstrukt übergeben wird.

t = Table(
    "mytable",
    metadata,
    Column("id", Integer, Sequence("id_seq", start=1), primary_key=True),
    Column(...),
    ...,
)

Dieser Schritt ist auch bei der Verwendung von Tabellenreflexion erforderlich, d.h. autoload_with=engine

t = Table(
    "mytable",
    metadata,
    Column("id", Integer, Sequence("id_seq", start=1), primary_key=True),
    autoload_with=engine,
)

Geändert in Version 1.4: `Identity`-Konstrukt in einer Column hinzugefügt, um die Option einer autoincrementing Spalte anzugeben.

Transaktionsisolationslevel / Autocommit

Oracle Database unterstützt die Isolationsmodi "READ COMMITTED" und "SERIALIZABLE". Der AUTOCOMMIT-Isolationslevel wird auch von den python-oracledb und cx_Oracle Dialekten unterstützt.

Einstellung über per-Verbindungs-Ausführungsoptionen

connection = engine.connect()
connection = connection.execution_options(isolation_level="AUTOCOMMIT")

Für READ COMMITTED und SERIALIZABLE setzt der Oracle Database Dialekt den Level auf Session-Ebene mit ALTER SESSION, der wieder auf seine Standardeinstellung zurückgesetzt wird, wenn die Verbindung an den Connection Pool zurückgegeben wird.

Gültige Werte für isolation_level sind

  • READ COMMITTED

  • AUTOCOMMIT

  • SERIALIZABLE

Hinweis

Die Implementierung für die Methode Connection.get_isolation_level(), wie sie von den Oracle Database Dialekten implementiert wird, erzwingt notwendigerweise den Start einer Transaktion unter Verwendung der Oracle Database DBMS_TRANSACTION.LOCAL_TRANSACTION_ID Funktion; andernfalls ist kein Level normalerweise lesbar.

Darüber hinaus löst die Methode Connection.get_isolation_level() eine Ausnahme aus, wenn die v$transaction Ansicht aufgrund von Berechtigungen oder aus anderen Gründen nicht verfügbar ist, was in Oracle Database Installationen ein häufiges Vorkommnis ist.

Die python-oracledb und cx_Oracle Dialekte versuchen, die Methode Connection.get_isolation_level() aufzurufen, wenn der Dialekt seine erste Verbindung zur Datenbank herstellt, um den "Standard"-Isolationslevel zu ermitteln. Dieser Standardlevel ist erforderlich, damit der Level nach einer vorübergehenden Änderung über die Methode Connection.execution_options() auf einer Verbindung zurückgesetzt werden kann. In dem häufigen Fall, dass die Methode Connection.get_isolation_level() aufgrund von nicht lesbarem v$transaction oder anderen datenbankbezogenen Fehlern eine Ausnahme auslöst, wird der Level auf "READ COMMITTED" gesetzt. Für diesen anfänglichen Erstverbindungsfall wird keine Warnung ausgegeben, da dies eine häufige Einschränkung bei Oracle-Datenbanken ist.

Neu in Version 1.3.16: Unterstützung für AUTOCOMMIT zum cx_Oracle Dialekt hinzugefügt, sowie die Vorstellung eines Standard-Isolationslevels.

Neu in Version 1.3.21: Unterstützung für SERIALIZABLE sowie Live-Lesen des Isolationslevels hinzugefügt.

Geändert in Version 1.3.22: Wenn der Standard-Isolationslevel aufgrund von Berechtigungen für die v$transaction Ansicht nicht gelesen werden kann, was bei Oracle-Installationen üblich ist, wird der Standard-Isolationslevel auf "READ COMMITTED" fest codiert, was dem Verhalten vor 1.3.21 entsprach.

Bezeichner-Groß-/Kleinschreibung

In Oracle Database stellt das Datenwörterbuch alle Groß-/Kleinschreibungsunempfindlichen Bezeichnernamen als Großbuchstaben dar. Dies steht im Widerspruch zu den Erwartungen von SQLAlchemy, das annimmt, dass ein Groß-/Kleinschreibungsunempfindlicher Name als Kleinbuchstaben dargestellt wird.

Als Beispiel für Groß-/Kleinschreibungsunempfindliche Bezeichnernamen, betrachten Sie die folgende Tabelle

CREATE TABLE MyTable (Identifier INTEGER PRIMARY KEY)

Wenn Sie Oracle Database nach Informationen über diese Tabelle abfragen würden, würde der Tabellenname als MYTABLE und der Spaltenname als IDENTIFIER gemeldet werden. Vergleichen Sie dies mit den meisten anderen Datenbanken wie PostgreSQL und MySQL, die diese Namen als mytable und identifier melden würden. Die Namen sind nicht in Anführungszeichen gesetzt, daher sind sie Groß-/Kleinschreibungsunempfindlich. Die spezielle Groß-/Kleinschreibung von MyTable und Identifier würde nur beibehalten, wenn sie in der Tabellendefinition in Anführungszeichen gesetzt wären.

CREATE TABLE "MyTable" ("Identifier" INTEGER PRIMARY KEY)

Beim Erstellen eines SQLAlchemy Table Objekts, wird ein vollständig kleingeschriebener Name als Groß-/Kleinschreibungsunempfindlich betrachtet. Die folgende Tabelle nimmt also Groß-/Kleinschreibungsunempfindliche Namen an.

Table("mytable", metadata, Column("identifier", Integer, primary_key=True))

Während bei gemischten oder GROSSBUCHSTABEN Namen Groß-/Kleinschreibung angenommen wird.

Table("MyTable", metadata, Column("Identifier", Integer, primary_key=True))

Eine ähnliche Situation tritt auf der Ebene des Datenbanktreibers auf, wenn eine textuelle SQL SELECT-Anweisung ausgegeben wird und Spaltennamen im DBAPI cursor.description Attribut betrachtet werden. Eine Datenbank wie PostgreSQL normalisiert Groß-/Kleinschreibungsunempfindliche Namen zu Kleinbuchstaben.

>>> pg_engine = create_engine("postgresql://scott:tiger@localhost/test")
>>> pg_connection = pg_engine.connect()
>>> result = pg_connection.exec_driver_sql("SELECT 1 AS SomeName")
>>> result.cursor.description
(Column(name='somename', type_code=23),)

Während Oracle sie zu GROSSBUCHSTABEN normalisiert.

>>> oracle_engine = create_engine("oracle+oracledb://scott:tiger@oracle18c/xe")
>>> oracle_connection = oracle_engine.connect()
>>> result = oracle_connection.exec_driver_sql(
...     "SELECT 1 AS SomeName FROM DUAL"
... )
>>> result.cursor.description
[('SOMENAME', <DbType DB_TYPE_NUMBER>, 127, None, 0, -127, True)]

Um die plattformübergreifende Gleichheit für die beiden Fälle a. Tabellenreflexion und b. rein textuelle SQL-Abfragen zu erreichen, führt SQLAlchemy einen Schritt namens Namensnormalisierung durch, wenn der Oracle-Dialekt verwendet wird. Dieser Prozess kann auch auf andere Drittanbieter-Dialekte angewendet werden, die eine ähnliche GROSSBUCHSTABEN-Handhabung von Groß-/Kleinschreibungsunempfindlichen Namen aufweisen.

Bei der Namensnormalisierung versucht SQLAlchemy zu erkennen, ob ein Name Groß-/Kleinschreibungsunempfindlich ist, indem es prüft, ob alle Zeichen GROSSBUCHSTABEN sind; falls ja, geht es davon aus, dass es sich um einen Groß-/Kleinschreibungsunempfindlichen Namen handelt und liefert ihn als kleingeschriebenen Namen aus.

Für die Tabellenreflexion wird angenommen, dass ein Tabellenname, der in den Oracle Database Katalogtabellen vollständig in GROSSBUCHSTABEN dargestellt wird, einen Groß-/Kleinschreibungsunempfindlichen Namen hat. Dies ermöglicht es der Table Definition, kleingeschriebene Namen zu verwenden und sowohl aus Sicht der Reflexion auf Oracle Database als auch auf allen anderen Datenbanken wie PostgreSQL und MySQL kompatibel zu sein.

# matches a table created with CREATE TABLE mytable
Table("mytable", metadata, autoload_with=some_engine)

Oben ist der kleingeschriebene Name "mytable" Groß-/Kleinschreibungsunempfindlich; er wird mit einer von PostgreSQL gemeldeten Tabelle "mytable" und einer von Oracle gemeldeten Tabelle "MYTABLE" übereinstimmen. Wenn keine Namensnormalisierung vorhanden wäre, wäre es für die obige Table Definition nicht möglich, Datenbank-übergreifend introspektierbar zu sein, da wir es mit einem Groß-/Kleinschreibungsunempfindlichen Namen zu tun haben, der von jeder Datenbank nicht auf die gleiche Weise gemeldet wird.

Die Groß-/Kleinschreibung kann in diesem Fall erzwungen werden, z. B. wenn wir den in Anführungszeichen gesetzten Tabellennamen "MYTABLE" mit genau dieser Schreibweise darstellen möchten, am einfachsten durch Verwendung dieser Schreibweise direkt, die als groß-/kleinschreibungssensitiv angesehen wird.

# matches a table created with CREATE TABLE "MYTABLE"
Table("MYTABLE", metadata, autoload_with=some_engine)

Für den ungewöhnlichen Fall eines in Anführungszeichen gesetzten, vollständig kleingeschriebenen Namens kann das Konstrukt quoted_name verwendet werden.

from sqlalchemy import quoted_name

# matches a table created with CREATE TABLE "mytable"
Table(
    quoted_name("mytable", quote=True), metadata, autoload_with=some_engine
)

Namensnormalisierung findet auch bei der Verarbeitung von Ergebnismengen aus rein textuellen SQL-Zeichenfolgen statt, die keine andere Table oder Column Metadaten zugeordnet haben. Dies schließt SQL-Zeichenfolgen ein, die mit Connection.exec_driver_sql() ausgeführt werden, und SQL-Zeichenfolgen, die mit dem Konstrukt text() ausgeführt werden, die keine Column Metadaten enthalten.

Wenn wir zur Oracle Database SELECT-Anweisung zurückkehren, sehen wir, dass obwohl cursor.description den Spaltennamen als SOMENAME meldet, SQLAlchemy dies zu somename normalisiert.

>>> oracle_engine = create_engine("oracle+oracledb://scott:tiger@oracle18c/xe")
>>> oracle_connection = oracle_engine.connect()
>>> result = oracle_connection.exec_driver_sql(
...     "SELECT 1 AS SomeName FROM DUAL"
... )
>>> result.cursor.description
[('SOMENAME', <DbType DB_TYPE_NUMBER>, 127, None, 0, -127, True)]
>>> result.keys()
RMKeyView(['somename'])

Das einzige Szenario, in dem das obige Verhalten ungenaue Ergebnisse liefert, ist die Verwendung eines vollständig großgeschriebenen, in Anführungszeichen gesetzten Namens. SQLAlchemy kann nicht feststellen, ob ein bestimmter Name in cursor.description in Anführungszeichen gesetzt wurde und daher groß-/kleinschreibungssensitiv ist, oder ob er nicht in Anführungszeichen gesetzt wurde und daher normalisiert werden sollte.

>>> result = oracle_connection.exec_driver_sql(
...     'SELECT 1 AS "SOMENAME" FROM DUAL'
... )
>>> result.cursor.description
[('SOMENAME', <DbType DB_TYPE_NUMBER>, 127, None, 0, -127, True)]
>>> result.keys()
RMKeyView(['somename'])

Für diesen Fall wird in SQLAlchemy 2.1 eine neue Funktion verfügbar sein, um das Namensnormalisierungsverhalten in bestimmten Fällen zu deaktivieren.

Maximale Bezeichnerlängen

SQLAlchemy ist empfindlich gegenüber der maximalen Bezeichnerlänge, die von Oracle Database unterstützt wird. Dies wirkt sich auf generierte SQL-Labelnamen sowie auf die Generierung von Constraint-Namen aus, insbesondere wenn die unter Konfiguration von Constraint-Benennungskonventionen beschriebene Funktion zur Benennung von Constraints verwendet wird.

Oracle Database 12.2 erhöhte die maximale Standardbezeichnerlänge von 30 auf 128. Ab SQLAlchemy 1.4 beträgt die maximale Standardbezeichnerlänge für die Oracle-Dialekte 128 Zeichen. Bei der ersten Verbindung wird die tatsächlich von der Datenbank unterstützte Maximallänge ermittelt. In allen Fällen umgeht die Einstellung des Parameters create_engine.max_identifier_length diese Änderung und der angegebene Wert wird unverändert verwendet.

engine = create_engine(
    "oracle+oracledb://scott:tiger@localhost:1521?service_name=freepdb1",
    max_identifier_length=30,
)

Wenn create_engine.max_identifier_length nicht gesetzt ist, verwendet der oracledb Dialekt intern das Attribut max_identifier_length, das auf Treiberverbindungen seit python-oracledb Version 2.5 verfügbar ist. Bei Verwendung einer älteren Treiberversion oder des cx_Oracle Dialekts versucht SQLAlchemy stattdessen, die Abfrage SELECT value FROM v$parameter WHERE name = 'compatible' bei der ersten Verbindung abzurufen, um die effektive Kompatibilitätsversion der Datenbank zu ermitteln. Die "Kompatibilitätsversion" ist eine Versionsnummer, die unabhängig von der tatsächlichen Datenbankversion ist. Sie wird zur Unterstützung von Datenbankmigrationen verwendet. Sie wird durch einen Oracle Database Initialisierungsparameter konfiguriert. Die Kompatibilitätsversion bestimmt dann die maximal zulässige Bezeichnerlänge für die Datenbank. Wenn die V$-Ansicht nicht verfügbar ist, wird stattdessen die Datenbankversionsinformation verwendet.

Die maximale Bezeichnerlänge kommt sowohl bei der Generierung von anonymisierten SQL-Labels in SELECT-Anweisungen als auch, was noch wichtiger ist, bei der Generierung von Constraint-Namen aus einer Benennungskonvention zum Tragen. Gerade in diesem Bereich besteht die Notwendigkeit, dass SQLAlchemy diese Standardeinstellung konservativ ändert. Zum Beispiel erzeugt die folgende Benennungskonvention zwei sehr unterschiedliche Constraint-Namen basierend auf der Bezeichnerlänge.

from sqlalchemy import Column
from sqlalchemy import Index
from sqlalchemy import Integer
from sqlalchemy import MetaData
from sqlalchemy import Table
from sqlalchemy.dialects import oracle
from sqlalchemy.schema import CreateIndex

m = MetaData(naming_convention={"ix": "ix_%(column_0N_name)s"})

t = Table(
    "t",
    m,
    Column("some_column_name_1", Integer),
    Column("some_column_name_2", Integer),
    Column("some_column_name_3", Integer),
)

ix = Index(
    None,
    t.c.some_column_name_1,
    t.c.some_column_name_2,
    t.c.some_column_name_3,
)

oracle_dialect = oracle.dialect(max_identifier_length=30)
print(CreateIndex(ix).compile(dialect=oracle_dialect))

Bei einer Bezeichnerlänge von 30 sieht der obige CREATE INDEX wie folgt aus:

CREATE INDEX ix_some_column_name_1s_70cd ON t
(some_column_name_1, some_column_name_2, some_column_name_3)

Mit einer Länge von 128 wird er jedoch zu:

.. sourcecode:: sql

CREATE INDEX ix_some_column_name_1some_column_name_2some_column_name_3 ON t (some_column_name_1, some_column_name_2, some_column_name_3)

Anwendungen, die Versionen von SQLAlchemy vor 1.4 auf Oracle Database Version 12.2 oder höher ausgeführt haben, sind daher von dem Szenario einer Datenbankmigration betroffen, die "DROP CONSTRAINT" auf einen Namen ausführen möchte, der zuvor mit der kürzeren Länge generiert wurde. Diese Migration schlägt fehl, wenn die Bezeichnerlänge geändert wird, ohne dass der Name des Index oder Constraints zuerst angepasst wird. Solchen Anwendungen wird dringend empfohlen, create_engine.max_identifier_length zu verwenden, um die Kontrolle über die Generierung abgeschnittener Namen zu behalten, und alle Datenbankmigrationen in einer Staging-Umgebung gründlich zu überprüfen und zu testen, wenn dieser Wert geändert wird, um sicherzustellen, dass die Auswirkungen dieser Änderung abgemildert wurden.

Geändert in Version 1.4: Die Standard-max_identifier_length für Oracle Database beträgt 128 Zeichen, die bei der ersten Verbindung auf 30 reduziert wird, wenn die Oracle Database oder ihre Kompatibilitätseinstellung niedriger als Version 12.2 sind.

LIMIT/OFFSET/FETCH Unterstützung

Methoden wie Select.limit() und Select.offset() verwenden die Syntax FETCH FIRST N ROW / OFFSET N ROWS unter der Annahme von Oracle Database 12c oder höher und unter der Annahme, dass die SELECT-Anweisung nicht in eine zusammengesetzte Anweisung wie UNION eingebettet ist. Diese Syntax ist auch direkt über die Methode Select.fetch() verfügbar.

Geändert in Version 2.0: Die Oracle Database Dialekte verwenden jetzt FETCH FIRST N ROW / OFFSET N ROWS für alle Select.limit() und Select.offset() Verwendungen, einschließlich innerhalb des ORM und des Legacy Query. Um das Legacy-Verhalten mithilfe von Fensterfunktionen zu erzwingen, geben Sie den Dialektparameter enable_offset_fetch=False an create_engine().

Die Verwendung von FETCH FIRST / OFFSET kann bei jeder Oracle Database Version deaktiviert werden, indem enable_offset_fetch=False an create_engine() übergeben wird, was den Modus "Legacy" erzwingt, der Fensterfunktionen verwendet. Dieser Modus wird auch automatisch ausgewählt, wenn eine Oracle Database Version vor 12c verwendet wird.

Bei der Verwendung des Legacy-Modus oder wenn eine Select Anweisung mit limit/offset in einer zusammengesetzten Anweisung eingebettet ist, wird ein emulierter Ansatz für LIMIT / OFFSET basierend auf Fensterfunktionen verwendet, der die Erstellung einer Unterabfrage mit ROW_NUMBER beinhaltet, die anfällig für Leistungsprobleme sowie Probleme bei der SQL-Konstruktion für komplexe Anweisungen ist. Dieser Ansatz wird jedoch von allen Oracle Database Versionen unterstützt. Siehe Hinweise unten.

Hinweise zur LIMIT / OFFSET Emulation (wenn die fetch() Methode nicht verwendet werden kann)

Bei Verwendung von Select.limit() und Select.offset(), oder im ORM die Methoden Query.limit() und Query.offset() auf einer Oracle Database Version vor 12c, gelten die folgenden Hinweise.

RETURNING Unterstützung

Oracle Database unterstützt RETURNING vollständig für INSERT-, UPDATE- und DELETE-Anweisungen, die mit einer einzelnen Sammlung von gebundenen Parametern aufgerufen werden (d. h. eine cursor.execute()-Stil-Anweisung; SQLAlchemy unterstützt im Allgemeinen kein RETURNING mit executemany Anweisungen). Mehrere Zeilen können ebenfalls zurückgegeben werden.

Geändert in Version 2.0: Das Oracle Database Backend hat vollständige Unterstützung für RETURNING im Einklang mit anderen Backends.

ON UPDATE CASCADE

Oracle Database hat keine native ON UPDATE CASCADE Funktionalität. Eine Trigger-basierte Lösung ist verfügbar unter https://web.archive.org/web/20090317041251/https://asktom.oracle.com/tkyte/update_cascade/index.html.

Bei Verwendung des SQLAlchemy ORM hat das ORM eine begrenzte Fähigkeit, Kaskadierende Updates manuell auszugeben - geben Sie ForeignKey-Objekte mit den Schlüsselwortargumenten "deferrable=True, initially='deferred'" an und geben Sie "passive_updates=False" für jede Beziehung an().

Oracle Database 8 Kompatibilität

Warnung

Der Status der Oracle Database 8 Kompatibilität ist für SQLAlchemy 2.0 unbekannt.

Wenn Oracle Database 8 erkannt wird, konfiguriert sich der Dialekt intern wie folgt:

  • Das Flag use_ansi wird auf False gesetzt. Dies hat den Effekt, alle JOIN-Phrasen in die WHERE-Klausel zu konvertieren und im Falle von LEFT OUTER JOIN den (+) Operator von Oracle zu verwenden.

  • Die Datentypen NVARCHAR2 und NCLOB werden nicht mehr als DDL generiert, wenn Unicode verwendet wird - stattdessen werden VARCHAR2 und CLOB ausgegeben. Dies liegt daran, dass diese Typen auf Oracle 8 anscheinend nicht korrekt funktionieren, obwohl sie verfügbar sind. Die Typen NVARCHAR und NCLOB werden immer NVARCHAR2 und NCLOB generieren.

Constraint-Reflexion

Die Oracle Database Dialekte können Informationen über Fremdschlüssel-, eindeutige und CHECK-Constraints sowie Indizes für Tabellen zurückgeben.

Rohinformationen zu diesen Constraints können über Inspector.get_foreign_keys(), Inspector.get_unique_constraints(), Inspector.get_check_constraints() und Inspector.get_indexes() abgerufen werden.

Geändert in Version 1.2: Der Oracle Database Dialekt kann nun UNIQUE- und CHECK-Constraints reflektieren.

Bei der Verwendung von Reflexion auf Table-Ebene werden diese Constraints auch in der Table enthalten sein.

Beachten Sie die folgenden Einschränkungen:

  • Bei der Verwendung der Methode Inspector.get_check_constraints() erstellt Oracle Database einen speziellen "IS NOT NULL"-Constraint für Spalten, die "NOT NULL" spezifizieren. Dieser Constraint wird standardmäßig nicht zurückgegeben. Um die "IS NOT NULL"-Constraints einzuschließen, übergeben Sie das Flag include_all=True.

    from sqlalchemy import create_engine, inspect
    
    engine = create_engine(
        "oracle+oracledb://scott:tiger@localhost:1521?service_name=freepdb1"
    )
    inspector = inspect(engine)
    all_check_constraints = inspector.get_check_constraints(
        "some_table", include_all=True
    )
  • In den meisten Fällen ist bei der Reflexion einer Table ein UNIQUE-Constraint nicht als UniqueConstraint Objekt verfügbar, da Oracle Database eindeutige Constraints in den meisten Fällen mit einem UNIQUE-Index spiegelt (die Ausnahme scheint zu sein, wenn zwei oder mehr eindeutige Constraints dieselben Spalten darstellen). Die Table stellt diese stattdessen über Index mit dem Flag unique=True dar.

  • Oracle Database erstellt einen impliziten Index für den Primärschlüssel einer Tabelle; dieser Index ist von allen Indexergebnissen ausgeschlossen.

  • Die Liste der für einen Index reflektierten Spalten enthält keine Spaltennamen, die mit SYS_NC beginnen.

Tabellennamen mit SYSTEM/SYSAUX Tablespaces

Die Methoden Inspector.get_table_names() und Inspector.get_temp_table_names() geben jeweils eine Liste von Tabellennamen für die aktuelle Engine zurück. Diese Methoden sind auch Teil der Reflexion, die innerhalb einer Operation wie MetaData.reflect() stattfindet. Standardmäßig schließen diese Operationen die Tabellenspaces SYSTEM und SYSAUX aus. Um dies zu ändern, kann die Standardliste der ausgeschlossenen Tabellenspaces auf Engine-Ebene über den Parameter exclude_tablespaces geändert werden.

# exclude SYSAUX and SOME_TABLESPACE, but not SYSTEM
e = create_engine(
    "oracle+oracledb://scott:tiger@localhost:1521/?service_name=freepdb1",
    exclude_tablespaces=["SYSAUX", "SOME_TABLESPACE"],
)

FLOAT / DOUBLE Unterstützung und Verhalten

Die SQLAlchemy Float und Double Datentypen sind generische Datentypen, die sich für ein bestimmtes Backend auf den "am wenigsten überraschenden" Datentyp auflösen. Für Oracle Database bedeutet dies, dass sie sich auf die Datentypen FLOAT und DOUBLE auflösen.

>>> from sqlalchemy import cast, literal, Float
>>> from sqlalchemy.dialects import oracle
>>> float_datatype = Float()
>>> print(cast(literal(5.0), float_datatype).compile(dialect=oracle.dialect()))
CAST(:param_1 AS FLOAT)

Die Datentypen FLOAT / DOUBLE von Oracle sind Aliase für NUMBER. Oracle Database speichert NUMBER-Werte mit voller Genauigkeit, nicht mit Gleitkomma-Genauigkeit, was bedeutet, dass FLOAT / DOUBLE sich nicht wirklich wie native FP-Werte verhalten. Oracle Database bietet stattdessen spezielle Datentypen BINARY_FLOAT und BINARY_DOUBLE, um echte 4- und 8-Byte-FP-Werte zu liefern.

SQLAlchemy unterstützt diese Datentypen direkt über BINARY_FLOAT und BINARY_DOUBLE. Um die Datentypen Float oder Double datenbankagnostisch zu verwenden und gleichzeitig Oracle-Backends die Nutzung eines dieser Typen zu ermöglichen, verwenden Sie die Methode TypeEngine.with_variant(), um eine Variante einzurichten.

>>> from sqlalchemy import cast, literal, Float
>>> from sqlalchemy.dialects import oracle
>>> float_datatype = Float().with_variant(oracle.BINARY_FLOAT(), "oracle")
>>> print(cast(literal(5.0), float_datatype).compile(dialect=oracle.dialect()))
CAST(:param_1 AS BINARY_FLOAT)

z. B. zur Verwendung dieses Datentyps in einer Table-Definition.

my_table = Table(
    "my_table",
    metadata,
    Column(
        "fp_data", Float().with_variant(oracle.BINARY_FLOAT(), "oracle")
    ),
)

DateTime-Kompatibilität

Oracle Database hat keinen Datentyp namens DATETIME, sondern nur DATE, der tatsächlich ein Datum und eine Uhrzeit speichern kann. Aus diesem Grund stellen die Oracle Database-Dialekte einen Typ DATE bereit, der eine Unterklasse von DateTime ist. Dieser Typ hat kein spezielles Verhalten und dient nur als "Markierung" für diesen Typ; zusätzlich wird, wenn eine Datenbankspalte reflektiert wird und der Typ als DATE gemeldet wird, der zeitsupportierende Typ DATE verwendet.

Oracle Database Tabellenoptionen

Die CREATE TABLE-Klausel unterstützt die folgenden Optionen mit Oracle Database-Dialekten in Verbindung mit dem Table-Konstrukt.

  • ON COMMIT:

    Table(
        "some_table",
        metadata,
        ...,
        prefixes=["GLOBAL TEMPORARY"],
        oracle_on_commit="PRESERVE ROWS",
    )
  • COMPRESS:

    Table(
        "mytable", metadata, Column("data", String(32)), oracle_compress=True
    )
    
    Table("mytable", metadata, Column("data", String(32)), oracle_compress=6)

    Der Parameter oracle_compress akzeptiert entweder eine Integer-Kompressionsstufe oder True, um die Standard-Kompressionsstufe zu verwenden.

  • TABLESPACE:

    Table("mytable", metadata, ..., oracle_tablespace="EXAMPLE_TABLESPACE")

    Der Parameter oracle_tablespace gibt den Tablespace an, in dem die Tabelle erstellt werden soll. Dies ist nützlich, wenn Sie eine Tabelle in einem anderen Tablespace als dem Standard-Tablespace des Benutzers erstellen möchten.

    Neu in Version 2.0.37.

Oracle Database spezifische Indexoptionen

Bitmap-Indizes

Sie können den Parameter oracle_bitmap angeben, um anstelle eines B-Tree-Index einen Bitmap-Index zu erstellen.

Index("my_index", my_table.c.data, oracle_bitmap=True)

Bitmap-Indizes können nicht eindeutig sein und nicht komprimiert werden. SQLAlchemy prüft diese Einschränkungen nicht, nur die Datenbank tut dies.

Indexkomprimierung

Oracle Database verfügt über einen effizienteren Speichermodus für Indizes mit vielen wiederholten Werten. Verwenden Sie den Parameter oracle_compress, um die Schlüsselkomprimierung zu aktivieren.

Index("my_index", my_table.c.data, oracle_compress=True)

Index(
    "my_index",
    my_table.c.data1,
    my_table.c.data2,
    unique=True,
    oracle_compress=1,
)

Der Parameter oracle_compress akzeptiert entweder eine ganze Zahl, die die Anzahl der zu komprimierenden Präfixspalten angibt, oder True, um den Standardwert zu verwenden (alle Spalten für nicht eindeutige Indizes, alle außer der letzten Spalte für eindeutige Indizes).

Oracle Database Datentypen

Wie bei allen SQLAlchemy-Dialekten sind alle GROSSGESCHRIEBENEN Typen, von denen bekannt ist, dass sie mit Oracle Database gültig sind, aus der obersten Ebene des Dialekts importierbar, unabhängig davon, ob sie aus sqlalchemy.types oder aus dem lokalen Dialekt stammen.

from sqlalchemy.dialects.oracle import (
    BFILE,
    BLOB,
    CHAR,
    CLOB,
    DATE,
    DOUBLE_PRECISION,
    FLOAT,
    INTERVAL,
    LONG,
    NCLOB,
    NCHAR,
    NUMBER,
    NVARCHAR,
    NVARCHAR2,
    RAW,
    TIMESTAMP,
    VARCHAR,
    VARCHAR2,
)

Neu in Version 1.2.19: NCHAR zur Liste der vom Oracle-Dialekt exportierten Datentypen hinzugefügt.

Typen, die spezifisch für Oracle Database sind oder Oracle-spezifische Konstruktorargumente haben, sind wie folgt:

Objektname Beschreibung

BFILE

BINARY_DOUBLE

Implementiert den Oracle BINARY_DOUBLE-Datentyp.

BINARY_FLOAT

Implementiert den Oracle BINARY_FLOAT-Datentyp.

DATE

Bietet den Oracle Database DATE-Typ.

FLOAT

Oracle Database FLOAT.

INTERVAL

LONG

NCLOB

NUMBER

NVARCHAR2

Alias für NVARCHAR

RAW

ROWID

Oracle Database ROWID-Typ.

TIMESTAMP

Oracle Database Implementierung von TIMESTAMP, die zusätzliche Oracle Database-spezifische Modi unterstützt.

Klasse sqlalchemy.dialects.oracle.BFILE

Mitglieder

__init__()

Methode sqlalchemy.dialects.oracle.BFILE.__init__(length: int | None = None)

geerbt von der sqlalchemy.types.LargeBinary.__init__ Methode von LargeBinary

Konstruiert einen LargeBinary-Typ.

Parameter:

length – optional, eine Länge für die Spalte zur Verwendung in DDL-Anweisungen für binäre Typen, die eine Länge akzeptieren, wie z. B. der MySQL BLOB-Typ.

Klasse sqlalchemy.dialects.oracle.BINARY_DOUBLE

Implementiert den Oracle BINARY_DOUBLE-Datentyp.

Dieser Datentyp unterscheidet sich vom Oracle DOUBLE-Datentyp darin, dass er einen echten 8-Byte-FP-Wert liefert. Der Datentyp kann mit einem generischen Double-Datentyp über TypeEngine.with_variant() kombiniert werden.

Mitglieder

__init__()

Methode sqlalchemy.dialects.oracle.BINARY_DOUBLE.__init__(precision: int | None = None, asdecimal: bool = False, decimal_return_scale: int | None = None)

geerbt von der sqlalchemy.types.Float.__init__ Methode von Float

Konstruiert einen Float.

Parameter:
  • precision

    die numerische Genauigkeit für die Verwendung in DDL CREATE TABLE. Backends **sollten** versuchen, diese Genauigkeit als Anzahl von Ziffern für den generischen Float-Datentyp anzugeben.

    Hinweis

    Für den Oracle Database-Backend wird der Parameter Float.precision bei der Wiedergabe von DDL nicht akzeptiert, da Oracle Database keine Float-Genauigkeit in Form von Dezimalstellen unterstützt. Verwenden Sie stattdessen den Oracle Database-spezifischen Datentyp FLOAT und geben Sie den Parameter FLOAT.binary_precision an. Dies ist neu in Version 2.0 von SQLAlchemy.

    Um einen datenbankagnostischen Float zu erstellen, der separat die binäre Genauigkeit für Oracle Database angibt, verwenden Sie TypeEngine.with_variant() wie folgt:

    from sqlalchemy import Column
    from sqlalchemy import Float
    from sqlalchemy.dialects import oracle
    
    Column(
        "float_data",
        Float(5).with_variant(oracle.FLOAT(binary_precision=16), "oracle"),
    )

  • asdecimal – das gleiche Flag wie bei Numeric, aber standardmäßig auf False gesetzt. Beachten Sie, dass das Setzen dieses Flags auf True zu einer Gleitkommakonvertierung führt.

  • decimal_return_scale – Skala, die standardmäßig beim Konvertieren von Gleitkommazahlen in Python-Dezimalzahlen verwendet wird. Gleitkommazahlen sind aufgrund von Dezimalungenauigkeiten typischerweise viel länger, und die meisten Gleitkomma-Datenbanktypen haben keine Vorstellung von "Skala". Daher sucht der Float-Typ standardmäßig nach den ersten zehn Dezimalstellen bei der Konvertierung. Die Angabe dieses Werts überschreibt diese Länge. Beachten Sie, dass die MySQL-Float-Typen, die "Skala" enthalten, "Skala" als Standard für decimal_return_scale verwenden, sofern nicht anders angegeben.

Klasse sqlalchemy.dialects.oracle.BINARY_FLOAT

Implementiert den Oracle BINARY_FLOAT-Datentyp.

Dieser Datentyp unterscheidet sich vom Oracle FLOAT-Datentyp darin, dass er einen echten 4-Byte-FP-Wert liefert. Der Datentyp kann mit einem generischen Float-Datentyp über TypeEngine.with_variant() kombiniert werden.

Mitglieder

__init__()

Methode sqlalchemy.dialects.oracle.BINARY_FLOAT.__init__(precision: int | None = None, asdecimal: bool = False, decimal_return_scale: int | None = None)

geerbt von der sqlalchemy.types.Float.__init__ Methode von Float

Konstruiert einen Float.

Parameter:
  • precision

    die numerische Genauigkeit für die Verwendung in DDL CREATE TABLE. Backends **sollten** versuchen, diese Genauigkeit als Anzahl von Ziffern für den generischen Float-Datentyp anzugeben.

    Hinweis

    Für den Oracle Database-Backend wird der Parameter Float.precision bei der Wiedergabe von DDL nicht akzeptiert, da Oracle Database keine Float-Genauigkeit in Form von Dezimalstellen unterstützt. Verwenden Sie stattdessen den Oracle Database-spezifischen Datentyp FLOAT und geben Sie den Parameter FLOAT.binary_precision an. Dies ist neu in Version 2.0 von SQLAlchemy.

    Um einen datenbankagnostischen Float zu erstellen, der separat die binäre Genauigkeit für Oracle Database angibt, verwenden Sie TypeEngine.with_variant() wie folgt:

    from sqlalchemy import Column
    from sqlalchemy import Float
    from sqlalchemy.dialects import oracle
    
    Column(
        "float_data",
        Float(5).with_variant(oracle.FLOAT(binary_precision=16), "oracle"),
    )

  • asdecimal – das gleiche Flag wie bei Numeric, aber standardmäßig auf False gesetzt. Beachten Sie, dass das Setzen dieses Flags auf True zu einer Gleitkommakonvertierung führt.

  • decimal_return_scale – Skala, die standardmäßig beim Konvertieren von Gleitkommazahlen in Python-Dezimalzahlen verwendet wird. Gleitkommazahlen sind aufgrund von Dezimalungenauigkeiten typischerweise viel länger, und die meisten Gleitkomma-Datenbanktypen haben keine Vorstellung von "Skala". Daher sucht der Float-Typ standardmäßig nach den ersten zehn Dezimalstellen bei der Konvertierung. Die Angabe dieses Werts überschreibt diese Länge. Beachten Sie, dass die MySQL-Float-Typen, die "Skala" enthalten, "Skala" als Standard für decimal_return_scale verwenden, sofern nicht anders angegeben.

Klasse sqlalchemy.dialects.oracle.DATE

Bietet den Oracle Database DATE-Typ.

Dieser Typ hat kein spezielles Python-Verhalten, außer dass er DateTime untererbt; dies liegt daran, dass der DATE-Typ von Oracle Database einen Zeitwert unterstützt.

Mitglieder

__init__()

Klassensignatur

class sqlalchemy.dialects.oracle.DATE (sqlalchemy.dialects.oracle.types._OracleDateLiteralRender, sqlalchemy.types.DateTime)

Methode sqlalchemy.dialects.oracle.DATE.__init__(timezone: bool = False)

geerbt von der sqlalchemy.types.DateTime.__init__ Methode von DateTime

Erstellt ein neues DateTime.

Parameter:

timezone – boolesch. Gibt an, dass der Datetime-Typ die Zeitzonenunterstützung aktivieren soll, falls dies im **Basisdatums/-zeit-Typ** verfügbar ist. Es wird empfohlen, direkt den Datentyp TIMESTAMP zu verwenden, da einige Datenbanken separate generische Datums-/Zeittypen aufweisen, die sich vom zeitzonenfähigen TIMESTAMP-Datentyp unterscheiden, wie z. B. Oracle Database.

Klasse sqlalchemy.dialects.oracle.FLOAT

Oracle Database FLOAT.

Dies ist dasselbe wie FLOAT, mit der Ausnahme, dass ein Oracle Database-spezifischer Parameter FLOAT.binary_precision akzeptiert wird und der Parameter Float.precision nicht akzeptiert wird.

Oracle Database FLOAT-Typen geben die Genauigkeit in "binärer Genauigkeit" an, die standardmäßig 126 beträgt. Für einen REAL-Typ beträgt der Wert 63. Dieser Parameter lässt sich nicht sauber auf eine bestimmte Anzahl von Dezimalstellen abbilden, entspricht aber ungefähr der gewünschten Anzahl von Dezimalstellen geteilt durch 0,3103.

Neu in Version 2.0.

Mitglieder

__init__()

Methode sqlalchemy.dialects.oracle.FLOAT.__init__(binary_precision=None, asdecimal=False, decimal_return_scale=None)

Erstellt einen FLOAT.

Parameter:
  • binary_precision – Oracle Database binäre Genauigkeit, die in DDL wiedergegeben wird. Dies kann durch die Formel "dezimale Genauigkeit = 0,30103 * binäre Genauigkeit" an die Anzahl der Dezimalstellen angenähert werden. Der von Oracle Database für FLOAT / DOUBLE PRECISION verwendete Standardwert ist 126.

  • asdecimal – Siehe Float.asdecimal

  • decimal_return_scale – Siehe Float.decimal_return_scale

Klasse sqlalchemy.dialects.oracle.INTERVAL

Mitglieder

__init__()

Klassensignatur

class sqlalchemy.dialects.oracle.INTERVAL (sqlalchemy.types.NativeForEmulated, sqlalchemy.types._AbstractInterval)

Methode sqlalchemy.dialects.oracle.INTERVAL.__init__(day_precision=None, second_precision=None)

Erstellt ein INTERVAL.

Beachten Sie, dass nur DAY TO SECOND-Intervalle unterstützt werden. Dies liegt an der fehlenden Unterstützung für YEAR TO MONTH-Intervalle in den verfügbaren DBAPIs.

Parameter:
  • day_precision – der Tag-Präzisionswert. Dies ist die Anzahl der Ziffern, die für das Tagesfeld gespeichert werden. Standardmäßig "2".

  • second_precision – der Sekunden-Präzisionswert. Dies ist die Anzahl der Ziffern, die für das Feld der Bruchteilsekunden gespeichert werden. Standardmäßig "6".

Klasse sqlalchemy.dialects.oracle.NCLOB

Mitglieder

__init__()

Methode sqlalchemy.dialects.oracle.NCLOB.__init__(length: int | None = None, collation: str | None = None)

geerbt von der sqlalchemy.types.String.__init__ Methode von String

Erstellt einen String-speichernden Typ.

Parameter:
  • length – optional, eine Länge für die Spalte zur Verwendung in DDL- und CAST-Ausdrücken. Kann sicher weggelassen werden, wenn kein CREATE TABLE ausgeführt wird. Bestimmte Datenbanken erfordern möglicherweise eine length für die Verwendung in DDL und lösen eine Ausnahme aus, wenn die CREATE TABLE DDL ausgeführt wird, wenn ein VARCHAR ohne Länge enthalten ist. Ob der Wert als Bytes oder Zeichen interpretiert wird, ist datenbankspezifisch.

  • collation

    Optional, eine Spalten-Kollation zur Verwendung in DDL- und CAST-Ausdrücken. Wird mit dem COLLATE-Schlüsselwort gerendert, das von SQLite, MySQL und PostgreSQL unterstützt wird. Z.B.

    >>> from sqlalchemy import cast, select, String
    >>> print(select(cast("some string", String(collation="utf8"))))
    
    SELECT CAST(:param_1 AS VARCHAR COLLATE utf8) AS anon_1

    Hinweis

    In den meisten Fällen sollten die Datentypen Unicode oder UnicodeText für eine Column verwendet werden, die nicht-ASCII-Daten speichern soll. Diese Datentypen stellen sicher, dass die korrekten Typen in der Datenbank verwendet werden.

Attribut sqlalchemy.dialects.oracle..sqlalchemy.dialects.oracle.NVARCHAR2

Alias für NVARCHAR

Klasse sqlalchemy.dialects.oracle.NUMBER
Klasse sqlalchemy.dialects.oracle.LONG

Mitglieder

__init__()

Methode sqlalchemy.dialects.oracle.LONG.__init__(length: int | None = None, collation: str | None = None)

geerbt von der sqlalchemy.types.String.__init__ Methode von String

Erstellt einen String-speichernden Typ.

Parameter:
  • length – optional, eine Länge für die Spalte zur Verwendung in DDL- und CAST-Ausdrücken. Kann sicher weggelassen werden, wenn kein CREATE TABLE ausgeführt wird. Bestimmte Datenbanken erfordern möglicherweise eine length für die Verwendung in DDL und lösen eine Ausnahme aus, wenn die CREATE TABLE DDL ausgeführt wird, wenn ein VARCHAR ohne Länge enthalten ist. Ob der Wert als Bytes oder Zeichen interpretiert wird, ist datenbankspezifisch.

  • collation

    Optional, eine Spalten-Kollation zur Verwendung in DDL- und CAST-Ausdrücken. Wird mit dem COLLATE-Schlüsselwort gerendert, das von SQLite, MySQL und PostgreSQL unterstützt wird. Z.B.

    >>> from sqlalchemy import cast, select, String
    >>> print(select(cast("some string", String(collation="utf8"))))
    
    SELECT CAST(:param_1 AS VARCHAR COLLATE utf8) AS anon_1

    Hinweis

    In den meisten Fällen sollten die Datentypen Unicode oder UnicodeText für eine Column verwendet werden, die nicht-ASCII-Daten speichern soll. Diese Datentypen stellen sicher, dass die korrekten Typen in der Datenbank verwendet werden.

Klasse sqlalchemy.dialects.oracle.RAW

Klassensignatur

class sqlalchemy.dialects.oracle.RAW (sqlalchemy.types._Binary)

Klasse sqlalchemy.dialects.oracle.ROWID

Oracle Database ROWID-Typ.

Beim Verwenden in einer cast() oder ähnlichem wird ROWID generiert.

Klasse sqlalchemy.dialects.oracle.TIMESTAMP

Oracle Database Implementierung von TIMESTAMP, die zusätzliche Oracle Database-spezifische Modi unterstützt.

Neu in Version 2.0.

Mitglieder

__init__()

Methode sqlalchemy.dialects.oracle.TIMESTAMP.__init__(timezone: bool = False, local_timezone: bool = False)

Konstruiert ein neues TIMESTAMP.

Parameter:
  • timezone – Boolean. Zeigt an, dass der TIMESTAMP-Typ den Datentyp TIMESTAMP WITH TIME ZONE der Oracle-Datenbank verwenden soll.

  • local_timezone – Boolean. Zeigt an, dass der TIMESTAMP-Typ den Datentyp TIMESTAMP WITH LOCAL TIME ZONE der Oracle-Datenbank verwenden soll.

python-oracledb

Unterstützung für die Oracle Database über den python-oracledb-Treiber.

DBAPI

Dokumentations- und Downloadinformationen (falls zutreffend) für python-oracledb sind verfügbar unter: https://oracle.github.io/python-oracledb/

Verbinden

Verbindungszeichenfolge

oracle+oracledb://user:pass@hostname:port[/dbname][?service_name=<service>[&key=value&key=value...]]

Beschreibung

Python-oracledb ist der Treiber für Oracle Database unter Python. Er verfügt über einen standardmäßigen „Thin“-Client-Modus, der keine Abhängigkeiten erfordert, und einen optionalen „Thick“-Modus, der Oracle Client-Bibliotheken verwendet. Er unterstützt SQLAlchemy-Funktionen, einschließlich Zweiphasentransaktionen und Asyncio.

Python-oracle ist der umbenannte, aktualisierte cx_Oracle-Treiber. Oracle veröffentlicht keine neuen Versionen mehr im cx_Oracle-Namespace.

Das SQLAlchemy oracledb-Dialekt bietet sowohl eine synchrone als auch eine asynchrone Implementierung unter demselben Dialektnamen. Die richtige Version wird ausgewählt, je nachdem, wie die Engine erstellt wird

  • Aufruf von create_engine() mit oracle+oracledb://... wählt automatisch die synchrone Version aus

    from sqlalchemy import create_engine
    
    sync_engine = create_engine(
        "oracle+oracledb://scott:tiger@localhost?service_name=FREEPDB1"
    )
  • Aufruf von create_async_engine() mit oracle+oracledb://... wählt automatisch die asynchrone Version aus

    from sqlalchemy.ext.asyncio import create_async_engine
    
    asyncio_engine = create_async_engine(
        "oracle+oracledb://scott:tiger@localhost?service_name=FREEPDB1"
    )

    Die Asyncio-Version des Dialekts kann auch explizit mit dem Suffix oracledb_async angegeben werden

    from sqlalchemy.ext.asyncio import create_async_engine
    
    asyncio_engine = create_async_engine(
        "oracle+oracledb_async://scott:tiger@localhost?service_name=FREEPDB1"
    )

Neu in Version 2.0.25: Unterstützung für die asynchrone Version von oracledb hinzugefügt.

Unterstützung für den Thick-Modus

Standardmäßig läuft der python-oracledb-Treiber im „Thin“-Modus, für den keine Oracle Client-Bibliotheken installiert sein müssen. Der Treiber unterstützt auch einen „Thick“-Modus, der Oracle Client-Bibliotheken verwendet, um Funktionalitäten wie Oracle Application Continuity zu nutzen.

Um den Thick-Modus zu aktivieren, rufen Sie oracledb.init_oracle_client() explizit auf oder übergeben Sie den Parameter thick_mode=True an create_engine(). Um benutzerdefinierte Argumente an init_oracle_client() zu übergeben, wie z. B. den lib_dir-Pfad, kann ein Dictionary übergeben werden, z. B.

engine = sa.create_engine(
    "oracle+oracledb://...",
    thick_mode={
        "lib_dir": "/path/to/oracle/client/lib",
        "config_dir": "/path/to/network_config_file_directory",
        "driver_name": "my-app : 1.0.0",
    },
)

Beachten Sie, dass die Angabe eines lib_dir-Pfades nur unter macOS oder Windows erfolgen sollte. Unter Linux funktioniert dies nicht wie erwartet.

Siehe auch

python-oracledb-Dokumentation Aktivieren des Thick-Modus von python-oracledb

Verbindung mit Oracle Database herstellen

python-oracledb bietet mehrere Möglichkeiten zur Angabe der Ziel-Datenbank. Der Dialekt übersetzt aus einer Reihe von verschiedenen URL-Formaten.

Bei Angabe von Hostname, Port und Servicename der Ziel-Datenbank können Sie sich in SQLAlchemy über den Abfragezeichenkettenparameter service_name verbinden

engine = create_engine(
    "oracle+oracledb://scott:tiger@hostname:port?service_name=myservice"
)

Verbindung mit Easy Connect-Zeichenketten herstellen

Sie können jede gültige python-oracledb-Verbindungszeichenkette als Wert für den Schlüssel dsn in einem create_engine.connect_args-Dictionary übergeben. Siehe die Dokumentation von python-oracledb zu Oracle Net Services Connection Strings.

Zum Beispiel zur Verwendung einer Easy Connect-Zeichenkette mit einem Timeout, um zu verhindern, dass die Verbindungsherstellung blockiert, wenn der Netzwerktransport zur Datenbank nicht innerhalb von 30 Sekunden hergestellt werden kann, und auch zur Einstellung einer Keep-Alive-Zeit von 60 Sekunden, um zu verhindern, dass inaktive Netzwerkverbindungen von einer Firewall beendet werden

e = create_engine(
    "oracle+oracledb://@",
    connect_args={
        "user": "scott",
        "password": "tiger",
        "dsn": "hostname:port/myservice?transport_connect_timeout=30&expire_time=60",
    },
)

Die Easy Connect-Syntax wurde im Laufe der Oracle Database weiterentwickelt. Überprüfen Sie die Dokumentation für Ihre Datenbankversion. Die aktuelle Dokumentation finden Sie unter Verständnis der Easy Connect-Namensgebungsmethode.

Die allgemeine Syntax ist ähnlich wie

[[protocol:]//]host[:port][/[service_name]][?parameter_name=value{&parameter_name=value}]

Beachten Sie, dass die SQLAlchemy-URL-Syntax hostname:port/dbname der Oracle Easy Connect-Syntax ähnelt, aber anders ist. SQLAlchemy-URLs erfordern einen Systembezeichner (SID) für die dbname-Komponente

engine = create_engine("oracle+oracledb://scott:tiger@hostname:port/sid")

Die Easy Connect-Syntax unterstützt keine SIDs. Sie verwendet Servicenamen, die für die Verbindung mit Oracle Database bevorzugt werden.

Übergabe von python-oracledb-Verbindungsargumenten

Andere Verbindungsoptionen des python-oracledb-Treibers können in connect_args übergeben werden. Zum Beispiel

e = create_engine(
    "oracle+oracledb://@",
    connect_args={
        "user": "scott",
        "password": "tiger",
        "dsn": "hostname:port/myservice",
        "events": True,
        "mode": oracledb.AUTH_MODE_SYSDBA,
    },
)

Verbindung mit tnsnames.ora TNS-Aliassen herstellen

Wenn kein Port, Datenbankname oder Servicename angegeben ist, verwendet der Dialekt eine Oracle Database DSN-„Verbindungszeichenkette“. Diese verwendet den „Hostname“-Teil der URL als Datenquellenname. Wenn beispielsweise die tnsnames.ora-Datei einen TNS-Alias namens myalias wie folgt enthält

myalias =
  (DESCRIPTION =
    (ADDRESS = (PROTOCOL = TCP)(HOST = mymachine.example.com)(PORT = 1521))
    (CONNECT_DATA =
      (SERVER = DEDICATED)
      (SERVICE_NAME = orclpdb1)
    )
  )

Der python-oracledb-Dialekt stellt eine Verbindung zu diesem Datenbankdienst her, wenn myalias der Hostname-Teil der URL ist, ohne Angabe eines Ports, Datenbanknamens oder service_name

engine = create_engine("oracle+oracledb://scott:tiger@myalias")

Verbindung mit Oracle Autonomous Database herstellen

Benutzer von Oracle Autonomous Database sollten entweder die oben gezeigte TNS-Alias-URL verwenden oder den TNS-Alias als Wert für den Schlüssel dsn in einem create_engine.connect_args-Dictionary übergeben.

Wenn Oracle Autonomous Database für gegenseitige TLS-„mTLS“-Verbindungen konfiguriert ist, sind zusätzliche Konfigurationen erforderlich, wie in Verbindung mit Oracle Cloud Autonomous Databases beschrieben. Zusammenfassend lässt sich sagen, dass Benutzer des Thick-Modus die Dateipfade konfigurieren und den Wallet-Pfad in sqlnet.ora entsprechend einstellen sollten

e = create_engine(
    "oracle+oracledb://@",
    thick_mode={
        # directory containing tnsnames.ora and cwallet.so
        "config_dir": "/opt/oracle/wallet_dir",
    },
    connect_args={
        "user": "scott",
        "password": "tiger",
        "dsn": "mydb_high",
    },
)

Benutzer des Thin-Modus von mTLS sollten die entsprechenden Verzeichnisse und das PEM-Wallet-Passwort beim Erstellen der Engine übergeben, ähnlich wie

e = create_engine(
    "oracle+oracledb://@",
    connect_args={
        "user": "scott",
        "password": "tiger",
        "dsn": "mydb_high",
        "config_dir": "/opt/oracle/wallet_dir",  # directory containing tnsnames.ora
        "wallet_location": "/opt/oracle/wallet_dir",  # directory containing ewallet.pem
        "wallet_password": "top secret",  # password for the PEM file
    },
)

Typischerweise sind config_dir und wallet_location dasselbe Verzeichnis, in das die Oracle Autonomous Database Wallet-Zip-Datei extrahiert wurde. Beachten Sie, dass dieses Verzeichnis geschützt sein sollte.

Verbindungspooling

Anwendungen mit mehreren gleichzeitigen Benutzern sollten Verbindungspooling verwenden. Ein Verbindungspool mit minimaler Größe ist auch für langlaufende Einzelbenutzeranwendungen von Vorteil, die keine häufige Verbindung verwenden.

Der python-oracledb-Treiber bietet eine eigene Implementierung des Verbindungspoolings, die anstelle der SQLAlchemy-Pooling-Funktionalität verwendet werden kann. Der Treiberpool unterstützt Hochverfügbarkeitsfunktionen wie die Erkennung von toten Verbindungen, das schrittweise Abschalten von Verbindungen für geplante Datenbankausfälle, die Unterstützung von Oracle Application Continuity und Transparent Application Continuity und bietet Unterstützung für Database Resident Connection Pooling (DRCP).

Um den pool von python-oracledb zu nutzen, verwenden Sie den Parameter create_engine.creator, um eine Funktion bereitzustellen, die eine neue Verbindung zurückgibt, und setzen Sie create_engine.pool_class auf NullPool, um das SQLAlchemy-Pooling zu deaktivieren

import oracledb
from sqlalchemy import create_engine
from sqlalchemy import text
from sqlalchemy.pool import NullPool

# Uncomment to use the optional python-oracledb Thick mode.
# Review the python-oracledb doc for the appropriate parameters
# oracledb.init_oracle_client(<your parameters>)

pool = oracledb.create_pool(
    user="scott",
    password="tiger",
    dsn="localhost:1521/freepdb1",
    min=1,
    max=4,
    increment=1,
)
engine = create_engine(
    "oracle+oracledb://", creator=pool.acquire, poolclass=NullPool
)

Die obige Engine kann dann normal verwendet werden. Intern verwaltet python-oracledb das Verbindungspooling

with engine.connect() as conn:
    print(conn.scalar(text("select 1 from dual")))

Beachten Sie die Dokumentation von python-oracledb für oracledb.create_pool() für die Argumente, die beim Erstellen eines Verbindungspools verwendet werden können.

Verwendung von Oracle Database Resident Connection Pooling (DRCP)

Bei der Verwendung von Oracle Database Resident Connection Pooling (DRCP) ist es am besten, eine Verbindungsklasse und „Purity“ anzugeben. Beachten Sie die Dokumentation von python-oracledb zu DRCP. Zum Beispiel

import oracledb
from sqlalchemy import create_engine
from sqlalchemy import text
from sqlalchemy.pool import NullPool

# Uncomment to use the optional python-oracledb Thick mode.
# Review the python-oracledb doc for the appropriate parameters
# oracledb.init_oracle_client(<your parameters>)

pool = oracledb.create_pool(
    user="scott",
    password="tiger",
    dsn="localhost:1521/freepdb1",
    min=1,
    max=4,
    increment=1,
    cclass="MYCLASS",
    purity=oracledb.PURITY_SELF,
)
engine = create_engine(
    "oracle+oracledb://", creator=pool.acquire, poolclass=NullPool
)

Die obige Engine kann dann normal verwendet werden, wobei python-oracledb das Anwendungspooling verwaltet und Oracle Database zusätzlich DRCP verwendet

with engine.connect() as conn:
    print(conn.scalar(text("select 1 from dual")))

Wenn Sie unterschiedliche Verbindungsklassen oder Puritys für verschiedene Verbindungen verwenden möchten, umschließen Sie pool.acquire()

import oracledb
from sqlalchemy import create_engine
from sqlalchemy import text
from sqlalchemy.pool import NullPool

# Uncomment to use python-oracledb Thick mode.
# Review the python-oracledb doc for the appropriate parameters
# oracledb.init_oracle_client(<your parameters>)

pool = oracledb.create_pool(
    user="scott",
    password="tiger",
    dsn="localhost:1521/freepdb1",
    min=1,
    max=4,
    increment=1,
    cclass="MYCLASS",
    purity=oracledb.PURITY_SELF,
)


def creator():
    return pool.acquire(cclass="MYOTHERCLASS", purity=oracledb.PURITY_NEW)


engine = create_engine(
    "oracle+oracledb://", creator=creator, poolclass=NullPool
)

Engine-Optionen, die vom SQLAlchemy oracledb-Dialekt außerhalb des Treibers verwendet werden

Es gibt auch Optionen, die vom SQLAlchemy oracledb-Dialekt selbst verbraucht werden. Diese Optionen werden immer direkt an create_engine() übergeben, wie z. B.

e = create_engine("oracle+oracledb://user:pass@tnsalias", arraysize=500)

Die vom oracledb-Dialekt akzeptierten Parameter sind folgende:

  • arraysize – Legt den Wert arraysize des Treibercursors fest. Standardmäßig ist dieser Wert None, was bedeutet, dass der Standardwert des Treibers von 100 verwendet wird. Diese Einstellung steuert, wie viele Zeilen beim Abrufen von Zeilen gepuffert werden, und kann sich erheblich auf die Leistung auswirken, wenn sie für Abfragen mit vielen Zeilen erhöht wird.

    Geändert in Version 2.0.26: Der Standardwert wurde von 50 auf None geändert, um den Standardwert des Treibers selbst zu verwenden.

  • auto_convert_lobs – Standardmäßig True; siehe LOB-Datentypen.

  • coerce_to_decimal – siehe Präzisions-Numerics für Details.

  • encoding_errors – siehe Encoding Errors für Details.

Unicode

Wie bei allen DBAPIs unter Python 3 sind alle Zeichenketten von Natur aus Unicode-Zeichenketten.

Sicherstellen der korrekten Client-Kodierung

In python-oracledb ist die Kodierung für alle Zeichendaten „UTF-8“.

Unicode-spezifische Spaltendatentypen

Die Core Expression Language verarbeitet Unicode-Daten mithilfe der Datentypen Unicode und UnicodeText. Diese Typen entsprechen standardmäßig den Oracle Database Datentypen VARCHAR2 und CLOB. Bei Verwendung dieser Datentypen mit Unicode-Daten wird erwartet, dass die Datenbank mit einer Unicode-fähigen Zeichensatzkonfiguration eingerichtet ist, damit die Datentypen VARCHAR2 und CLOB die Daten aufnehmen können.

Wenn die Oracle Database nicht mit einem Unicode-Zeichensatz konfiguriert ist, bestehen die beiden Optionen darin, die Datentypen NCHAR und NCLOB explizit zu verwenden oder das Flag use_nchar_for_unicode=True an create_engine() zu übergeben, was dazu führt, dass der SQLAlchemy-Dialekt NCHAR/NCLOB für die Datentypen Unicode / UnicodeText anstelle von VARCHAR/CLOB verwendet.

Geändert in Version 1.3: Die Datentypen Unicode und UnicodeText entsprechen nun den Oracle Database Datentypen VARCHAR2 und CLOB, es sei denn, use_nchar_for_unicode=True wird beim Aufruf von create_engine() an den Dialekt übergeben.

Encoding Errors

Für den ungewöhnlichen Fall, dass Daten in der Oracle-Datenbank mit einer beschädigten Kodierung vorhanden sind, akzeptiert der Dialekt einen Parameter encoding_errors, der an die Unicode-Dekodierungsfunktionen weitergegeben wird, um zu beeinflussen, wie Dekodierungsfehler behandelt werden. Der Wert wird letztendlich von der Python decode-Funktion verbraucht und sowohl über den Parameter encodingErrors von python-oracledb, der von Cursor.var() verbraucht wird, als auch über die eigene Dekodierungsfunktion von SQLAlchemy weitergegeben, da der python-oracledb-Dialekt beides unter verschiedenen Umständen nutzt.

Neu ab Version 1.3.11.

Feingranulare Steuerung der python-oracledb-Datenbindung mit setinputsizes

Die python-oracle DBAPI hat eine tiefe und grundlegende Abhängigkeit von der Verwendung des DBAPI-Aufrufs setinputsizes(). Der Zweck dieses Aufrufs ist es, die Datentypen festzulegen, die an eine SQL-Anweisung für Python-Werte gebunden werden, die als Parameter übergeben werden. Während praktisch kein anderer DBAPI dem setinputsizes()-Aufruf irgendeine Verwendung zuweist, ist die python-oracledb DBAPI in ihren Interaktionen mit der Oracle-Datenbank stark darauf angewiesen, und in einigen Szenarien ist es für SQLAlchemy nicht möglich, genau zu wissen, wie Daten gebunden werden sollen, da einige Einstellungen zu sehr unterschiedlichen Leistungseigenschaften führen können, während sich gleichzeitig das Verhalten der Typumwandlung ändert.

Benutzer des oracledb-Dialekts werden **dringend aufgefordert**, die Liste der integrierten Datentyp-Symbole von python-oracledb unter Datenbanktypen zu lesen. Beachten Sie, dass in einigen Fällen erhebliche Leistungseinbußen auftreten können, wenn diese Typen verwendet werden im Vergleich zur Nichtverwendung.

Auf der SQLAlchemy-Seite kann das Ereignis DialectEvents.do_setinputsizes() sowohl für die Laufzeitsichtbarkeit (z. B. Protokollierung) des setinputsizes-Schritts als auch zur vollständigen Steuerung der Verwendung von setinputsizes() pro Anweisung verwendet werden.

Neu in Version 1.2.9: DialectEvents.setinputsizes() hinzugefügt

Beispiel 1 – Protokollierung aller setinputsizes-Aufrufe

Das folgende Beispiel zeigt, wie die Zwischenwerte aus SQLAlchemy-Perspektive protokolliert werden, bevor sie in das rohe setinputsizes()-Parameter-Dictionary konvertiert werden. Die Schlüssel des Dictionaries sind BindParameter-Objekte, die ein .key- und ein .type-Attribut haben

from sqlalchemy import create_engine, event

engine = create_engine(
    "oracle+oracledb://scott:tiger@localhost:1521?service_name=freepdb1"
)


@event.listens_for(engine, "do_setinputsizes")
def _log_setinputsizes(inputsizes, cursor, statement, parameters, context):
    for bindparam, dbapitype in inputsizes.items():
        log.info(
            "Bound parameter name: %s  SQLAlchemy type: %r DBAPI object: %s",
            bindparam.key,
            bindparam.type,
            dbapitype,
        )

Beispiel 2 – Entfernen aller Bindungen zu CLOB

Aus Leistungsgründen ist das Abrufen von LOB-Datentypen aus der Oracle-Datenbank standardmäßig für den Text-Typ in SQLAlchemy eingestellt. Diese Einstellung kann wie folgt geändert werden

from sqlalchemy import create_engine, event
from oracledb import CLOB

engine = create_engine(
    "oracle+oracledb://scott:tiger@localhost:1521?service_name=freepdb1"
)


@event.listens_for(engine, "do_setinputsizes")
def _remove_clob(inputsizes, cursor, statement, parameters, context):
    for bindparam, dbapitype in list(inputsizes.items()):
        if dbapitype is CLOB:
            del inputsizes[bindparam]

LOB-Datentypen

LOB-Datentypen beziehen sich auf die „Large Object“-Datentypen wie CLOB, NCLOB und BLOB. Oracle Database kann diese Datentypen effizient als einen einzigen Puffer zurückgeben. SQLAlchemy nutzt standardmäßig Typ-Handler, um dies zu tun.

Um die Verwendung der Typ-Handler zu deaktivieren und LOB-Objekte als klassische gepufferte Objekte mit einer read()-Methode zu liefern, kann der Parameter auto_convert_lobs=False an create_engine() übergeben werden.

RETURNING-Unterstützung

Der oracledb-Dialekt implementiert RETURNING mit OUT-Parametern. Der Dialekt unterstützt RETURNING vollständig.

Zweiphasentransaktionsunterstützung

Zweiphasentransaktionen werden mit python-oracledb vollständig unterstützt. (Der Thin-Modus erfordert python-oracledb 2.3). APIs für Zweiphasentransaktionen sind auf der Core-Ebene über Connection.begin_twophase() und Session.twophase für transparente ORM-Nutzung verfügbar.

Geändert in Version 2.0.32: Unterstützung für Zweiphasentransaktionen hinzugefügt

Präzisions-Numerics

SQLAlchemy-numerische Typen können Werte als Python Decimal-Objekte oder Float-Objekte empfangen und zurückgeben. Wenn ein Numeric-Objekt oder eine Unterklasse wie Float, DOUBLE_PRECISION usw. verwendet wird, bestimmt das Flag Numeric.asdecimal, ob Werte bei der Rückgabe zu Decimal konvertiert oder als Float-Objekte zurückgegeben werden sollen. Um die Sache unter Oracle Database zu erschweren, kann der NUMBER-Typ auch Ganzzahlen darstellen, wenn die „Skala“ Null ist. Der Oracle-spezifische Typ NUMBER berücksichtigt dies ebenfalls.

Der oracledb-Dialekt verwendet intensiv auf Verbindungs- und Cursor-Ebene „outputtypehandler“-Aufrufbare, um numerische Werte wie gewünscht zu konvertieren. Diese Aufrufbaren sind spezifisch für die jeweilige Variante von Numeric sowie wenn keine SQLAlchemy-Typobjekte vorhanden sind. Es gibt beobachtete Szenarien, in denen Oracle Database unvollständige oder mehrdeutige Informationen über die zurückgegebenen numerischen Typen sendet, wie z. B. eine Abfrage, bei der die numerischen Typen unter mehreren Ebenen von Unterabfragen versteckt sind. Die Typ-Handler tun ihr Bestes, um in allen Fällen die richtige Entscheidung zu treffen, und weichen auf den zugrunde liegenden python-oracledb DBAPI für alle Fälle zurück, in denen der Treiber die beste Entscheidung treffen kann.

Wenn keine Typobjekte vorhanden sind, wie bei der Ausführung von reinen SQL-Zeichenketten, ist ein Standard-„outputtypehandler“ vorhanden, der im Allgemeinen numerische Werte zurückgibt, die Präzision und Skala als Python Decimal-Objekte angeben. Um diese Konvertierung nach Decimal aus Leistungsgründen zu deaktivieren, übergeben Sie das Flag coerce_to_decimal=False an create_engine()

engine = create_engine(
    "oracle+oracledb://scott:tiger@tnsalias", coerce_to_decimal=False
)

Das Flag coerce_to_decimal beeinflusst nur die Ergebnisse von reinen SQL-Zeichenkettenanweisungen, die nicht anderweitig mit einem Numeric SQLAlchemy-Typ (oder einer Unterklasse davon) verknüpft sind.

Geändert in Version 1.2: Das System zur Handhabung von Zahlen für die Oracle-Dialekte wurde überarbeitet, um neuere Treiberfunktionen sowie eine bessere Integration von Output-Handlern zu nutzen.

Neu in Version 2.0.0: Unterstützung für den python-oracledb-Treiber hinzugefügt.

cx_Oracle

Unterstützung für die Oracle Database über den cx-Oracle-Treiber.

DBAPI

Dokumentations- und Downloadinformationen (falls zutreffend) für cx-Oracle sind verfügbar unter: https://oracle.github.io/python-cx_Oracle/

Verbinden

Verbindungszeichenfolge

oracle+cx_oracle://user:pass@hostname:port[/dbname][?service_name=<service>[&key=value&key=value...]]

Beschreibung

cx_Oracle war der ursprüngliche Treiber für Oracle Database. Er wurde durch python-oracledb abgelöst, das stattdessen verwendet werden sollte.

DSN vs. Hostname-Verbindungen

cx_Oracle bietet mehrere Möglichkeiten zur Angabe der Ziel-Datenbank. Der Dialekt übersetzt aus einer Reihe von verschiedenen URL-Formen.

Hostname-Verbindungen mit Easy Connect-Syntax

Bei Angabe von Hostname, Port und Servicename der Ziel-Datenbank, zum Beispiel aus der Oracle Database Easy Connect-Syntax, verbinden Sie sich in SQLAlchemy über den Abfragezeichenkettenparameter service_name

engine = create_engine(
    "oracle+cx_oracle://scott:tiger@hostname:port?service_name=myservice&encoding=UTF-8&nencoding=UTF-8"
)

Beachten Sie, dass der Standardtreiberwert für Encoding und Nencoding in cx_Oracle 8.0 auf „UTF-8“ geändert wurde, sodass diese Parameter bei Verwendung dieser oder späterer Versionen weggelassen werden können.

Um eine vollständige Easy Connect-Zeichenkette zu verwenden, übergeben Sie sie als Wert für den Schlüssel dsn in einem create_engine.connect_args-Dictionary

import cx_Oracle

e = create_engine(
    "oracle+cx_oracle://@",
    connect_args={
        "user": "scott",
        "password": "tiger",
        "dsn": "hostname:port/myservice?transport_connect_timeout=30&expire_time=60",
    },
)

Verbindungen mit tnsnames.ora oder zu Oracle Autonomous Database

Alternativ, wenn kein Port, Datenbankname oder Servicename angegeben ist, verwendet der Dialekt eine Oracle Database DSN-„Verbindungszeichenkette“. Diese verwendet den „Hostname“-Teil der URL als Datenquellenname. Wenn beispielsweise die tnsnames.ora-Datei einen TNS-Alias namens myalias wie folgt enthält

myalias =
  (DESCRIPTION =
    (ADDRESS = (PROTOCOL = TCP)(HOST = mymachine.example.com)(PORT = 1521))
    (CONNECT_DATA =
      (SERVER = DEDICATED)
      (SERVICE_NAME = orclpdb1)
    )
  )

Der cx_Oracle-Dialekt stellt eine Verbindung zu diesem Datenbankdienst her, wenn myalias der Hostname-Teil der URL ist, ohne Angabe eines Ports, Datenbanknamens oder service_name

engine = create_engine("oracle+cx_oracle://scott:tiger@myalias")

Benutzer von Oracle Autonomous Database sollten diese Syntax verwenden. Wenn die Datenbank für mTLS-Verbindungen konfiguriert ist, müssen Sie auch das Cloud-Wallet wie in der cx_Oracle-Dokumentation unter Verbindung mit autonomen Datenbanken beschrieben konfigurieren.

SID-Verbindungen

Um die veraltete System-Identifier-Verbindungssyntax von Oracle Database zu verwenden, kann die SID im „Datenbankname“-Teil der URL übergeben werden

engine = create_engine(
    "oracle+cx_oracle://scott:tiger@hostname:port/dbname"
)

Oben wird die an cx_Oracle übergebene DSN von cx_Oracle.makedsn() wie folgt erstellt:

>>> import cx_Oracle
>>> cx_Oracle.makedsn("hostname", 1521, sid="dbname")
'(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=hostname)(PORT=1521))(CONNECT_DATA=(SID=dbname)))'

Beachten Sie, dass die SQLAlchemy-Syntax hostname:port/dbname der Oracle Easy Connect-Syntax ähnelt, aber anders ist. Sie verwendet eine SID anstelle des von Easy Connect benötigten Servicenamens. Die Easy Connect-Syntax unterstützt keine SIDs.

Übergabe von cx_Oracle-Verbindungsargumenten

Zusätzliche Verbindungsargumente können normalerweise über die URL-Abfragezeichenkette übergeben werden; bestimmte Symbole wie SYSDBA werden abgefangen und in das korrekte Symbol konvertiert

e = create_engine(
    "oracle+cx_oracle://user:pass@dsn?encoding=UTF-8&nencoding=UTF-8&mode=SYSDBA&events=true"
)

Geändert in Version 1.3: Der cx_Oracle-Dialekt akzeptiert nun alle Argumentnamen innerhalb der URL-Zeichenkette selbst, die an die cx_Oracle DBAPI übergeben werden. Wie bereits zuvor, aber nicht korrekt dokumentiert, akzeptiert der Parameter create_engine.connect_args ebenfalls alle cx_Oracle DBAPI-Verbindungsargumente.

Um Argumente direkt an .connect() zu übergeben, ohne die Abfragezeichenkette zu verwenden, verwenden Sie das Dictionary create_engine.connect_args. Beliebige cx_Oracle-Parameterwerte und/oder Konstanten können übergeben werden, wie z. B.

import cx_Oracle

e = create_engine(
    "oracle+cx_oracle://user:pass@dsn",
    connect_args={
        "encoding": "UTF-8",
        "nencoding": "UTF-8",
        "mode": cx_Oracle.SYSDBA,
        "events": True,
    },
)

Beachten Sie, dass der Standardtreiberwert für encoding und nencoding in cx_Oracle 8.0 auf „UTF-8“ geändert wurde, sodass diese Parameter bei Verwendung dieser oder späterer Versionen weggelassen werden können.

Optionen, die vom SQLAlchemy cx_Oracle-Dialekt außerhalb des Treibers verwendet werden

Es gibt auch Optionen, die vom SQLAlchemy cx_oracle Dialekt selbst verbraucht werden. Diese Optionen werden immer direkt an create_engine() übergeben, wie z. B.

e = create_engine(
    "oracle+cx_oracle://user:pass@dsn", coerce_to_decimal=False
)

Die vom cx_oracle Dialekt akzeptierten Parameter sind wie folgt:

  • arraysize - setzt den Wert von cx_oracle.arraysize auf Cursors; Standard ist None, was bedeutet, dass der Standardtreiber verwendet wird (typischerweise ist der Wert 100). Diese Einstellung steuert, wie viele Zeilen beim Abrufen von Zeilen gepuffert werden, und kann sich bei Änderungen erheblich auf die Leistung auswirken.

    Geändert in Version 2.0.26: Der Standardwert wurde von 50 auf None geändert, um den Standardwert des Treibers selbst zu verwenden.

  • auto_convert_lobs - Standard ist True; Siehe LOB-Datentypen.

  • coerce_to_decimal - siehe Präzisions-Numeriken für Details.

  • encoding_errors - siehe Encoding-Fehler für Details.

Verwendung des cx_Oracle SessionPool

Der cx_Oracle-Treiber bietet eine eigene Implementierung eines Connection Pools, die anstelle der Pooling-Funktionalität von SQLAlchemy verwendet werden kann. Der Treiber-Pool unterstützt Oracle Database-Funktionen wie die Erkennung toter Verbindungen, das "Draining" von Verbindungen für geplante Datenbankausfallzeiten, die Unterstützung für Oracle Application Continuity und Transparent Application Continuity sowie die Unterstützung für Database Resident Connection Pooling (DRCP).

Die Verwendung des Treiber-Pools kann durch die Angabe des Parameters create_engine.creator erreicht werden, um eine Funktion bereitzustellen, die eine neue Verbindung zurückgibt, sowie durch die Einstellung von create_engine.pool_class auf NullPool, um das Pooling von SQLAlchemy zu deaktivieren.

import cx_Oracle
from sqlalchemy import create_engine
from sqlalchemy.pool import NullPool

pool = cx_Oracle.SessionPool(
    user="scott",
    password="tiger",
    dsn="orclpdb",
    min=1,
    max=4,
    increment=1,
    threaded=True,
    encoding="UTF-8",
    nencoding="UTF-8",
)

engine = create_engine(
    "oracle+cx_oracle://", creator=pool.acquire, poolclass=NullPool
)

Die oben genannte Engine kann dann normal verwendet werden, wobei der cx_Oracle-Pool das Verbindungs-Pooling übernimmt.

with engine.connect() as conn:
    print(conn.scalar("select 1 from dual"))

Neben der Bereitstellung einer skalierbaren Lösung für Multi-User-Anwendungen unterstützt der cx_Oracle Session Pool einige Oracle-Funktionen wie DRCP und Application Continuity.

Beachten Sie, dass die Parameter für die Pool-Erstellung threaded, encoding und nencoding in späteren cx_Oracle-Versionen als veraltet markiert wurden.

Verwendung von Oracle Database Resident Connection Pooling (DRCP)

Bei der Verwendung von DRCP der Oracle-Datenbank ist es bewährte Praxis, beim Abrufen einer Verbindung aus dem SessionPool eine Verbindungsklasse und "purity" zu übergeben. Beachten Sie die cx_Oracle DRCP-Dokumentation.

Dies kann durch Umschließen von pool.acquire() erreicht werden.

import cx_Oracle
from sqlalchemy import create_engine
from sqlalchemy.pool import NullPool

pool = cx_Oracle.SessionPool(
    user="scott",
    password="tiger",
    dsn="orclpdb",
    min=2,
    max=5,
    increment=1,
    threaded=True,
    encoding="UTF-8",
    nencoding="UTF-8",
)


def creator():
    return pool.acquire(
        cclass="MYCLASS", purity=cx_Oracle.ATTR_PURITY_SELF
    )


engine = create_engine(
    "oracle+cx_oracle://", creator=creator, poolclass=NullPool
)

Die oben genannte Engine kann dann normal verwendet werden, wobei cx_Oracle das Session-Pooling übernimmt und die Oracle-Datenbank zusätzlich DRCP verwendet.

with engine.connect() as conn:
    print(conn.scalar("select 1 from dual"))

Unicode

Wie bei allen DBAPIs unter Python 3 sind alle Zeichenketten inhärent Unicode-Zeichenketten. In allen Fällen benötigt der Treiber jedoch eine explizite Codierungskonfiguration.

Sicherstellung der korrekten Client-Codierung

Der lange etablierte Standard zur Festlegung der Client-Codierung für fast alle Oracle-Datenbank-bezogenen Software ist über die Umgebungsvariable NLS_LANG. Ältere Versionen von cx_Oracle verwenden diese Umgebungsvariable als Quelle ihrer Codierungskonfiguration. Das Format dieser Variablen ist Territory_Country.CharacterSet; ein typischer Wert wäre AMERICAN_AMERICA.AL32UTF8. cx_Oracle Version 8 und neuer verwenden standardmäßig die Zeichensatz "UTF-8" und ignorieren die Zeichensatzkomponente von NLS_LANG.

Der cx_Oracle-Treiber unterstützte auch eine programmatische Alternative, nämlich die Übergabe der Parameter encoding und nencoding direkt an seine Funktion .connect(). Diese können in der URL wie folgt vorhanden sein:

engine = create_engine(
    "oracle+cx_oracle://scott:tiger@tnsalias?encoding=UTF-8&nencoding=UTF-8"
)

Die Bedeutung der Parameter encoding und nencoding finden Sie unter Zeichensätze und National Language Support (NLS).

Siehe auch

Zeichensätze und National Language Support (NLS) - in der cx_Oracle-Dokumentation.

Unicode-spezifische Spaltendatentypen

Die Core Expression Language verarbeitet Unicode-Daten mithilfe der Datentypen Unicode und UnicodeText. Diese Typen entsprechen standardmäßig den Oracle Database-Datentypen VARCHAR2 und CLOB. Bei der Verwendung dieser Datentypen mit Unicode-Daten wird erwartet, dass die Datenbank mit einem Unicode-fähigen Zeichensatz konfiguriert ist und dass die Umgebungsvariable NLS_LANG entsprechend gesetzt ist (dies gilt für ältere Versionen von cx_Oracle), damit die Datentypen VARCHAR2 und CLOB die Daten aufnehmen können.

Wenn die Oracle Database nicht mit einem Unicode-Zeichensatz konfiguriert ist, bestehen die beiden Optionen darin, die Datentypen NCHAR und NCLOB explizit zu verwenden oder das Flag use_nchar_for_unicode=True an create_engine() zu übergeben, was dazu führt, dass der SQLAlchemy-Dialekt NCHAR/NCLOB für die Datentypen Unicode / UnicodeText anstelle von VARCHAR/CLOB verwendet.

Geändert in Version 1.3: Die Datentypen Unicode und UnicodeText entsprechen nun den Oracle Database Datentypen VARCHAR2 und CLOB, es sei denn, use_nchar_for_unicode=True wird beim Aufruf von create_engine() an den Dialekt übergeben.

Encoding-Fehler

Für den ungewöhnlichen Fall, dass Daten in der Oracle-Datenbank mit einem fehlerhaften Encoding vorhanden sind, akzeptiert der Dialekt den Parameter encoding_errors, der an Unicode-Dekodierungsfunktionen übergeben wird, um zu beeinflussen, wie Dekodierungsfehler behandelt werden. Der Wert wird letztendlich von der Python-Funktion decode verbraucht und wird sowohl über den cx_Oracle-Parameter encodingErrors, der von Cursor.var() verbraucht wird, als auch über die eigene Dekodierungsfunktion von SQLAlchemy übergeben, da der cx_Oracle-Dialekt diese unter verschiedenen Umständen nutzt.

Neu ab Version 1.3.11.

Feingranulare Steuerung der Leistung der cx_Oracle-Datenbindung mit setinputsizes

Der cx_Oracle DBAPI hat eine tiefe und grundlegende Abhängigkeit von der Verwendung des DBAPI-Aufrufs setinputsizes(). Der Zweck dieses Aufrufs ist es, die Datentypen festzulegen, die an eine SQL-Anweisung für Python-Werte gebunden werden, die als Parameter übergeben werden. Während praktisch kein anderer DBAPI dem setinputsizes()-Aufruf eine Verwendung zuweist, verlässt sich der cx_Oracle DBAPI stark darauf in seiner Interaktion mit der Oracle Database-Client-Schnittstelle, und in einigen Szenarien ist es für SQLAlchemy nicht möglich, genau zu wissen, wie Daten gebunden werden sollen, da einige Einstellungen tiefgreifend unterschiedliche Leistungseigenschaften aufweisen und gleichzeitig das Typumwandlungsverhalten ändern können.

Benutzer des cx_Oracle-Dialekts werden **dringend gebeten**, die Liste der integrierten Datentypsymbole von cx_Oracle unter https://cx-oracle.readthedocs.io/en/latest/api_manual/module.html#database-types zu lesen. Beachten Sie, dass in einigen Fällen signifikante Leistungsabfälle auftreten können, wenn diese Typen verwendet werden im Vergleich zur Nichtverwendung, insbesondere bei der Angabe von cx_Oracle.CLOB.

Auf der SQLAlchemy-Seite kann das Ereignis DialectEvents.do_setinputsizes() sowohl für die Laufzeitsichtbarkeit (z. B. Protokollierung) des setinputsizes-Schritts als auch zur vollständigen Steuerung der Verwendung von setinputsizes() pro Anweisung verwendet werden.

Neu in Version 1.2.9: DialectEvents.setinputsizes() hinzugefügt

Beispiel 1 - Protokollierung aller setinputsizes-Aufrufe

Das folgende Beispiel zeigt, wie die Zwischenwerte aus SQLAlchemy-Perspektive protokolliert werden, bevor sie in das rohe setinputsizes()-Parameter-Dictionary konvertiert werden. Die Schlüssel des Dictionaries sind BindParameter-Objekte, die ein .key- und ein .type-Attribut haben

from sqlalchemy import create_engine, event

engine = create_engine("oracle+cx_oracle://scott:tiger@host/xe")


@event.listens_for(engine, "do_setinputsizes")
def _log_setinputsizes(inputsizes, cursor, statement, parameters, context):
    for bindparam, dbapitype in inputsizes.items():
        log.info(
            "Bound parameter name: %s  SQLAlchemy type: %r DBAPI object: %s",
            bindparam.key,
            bindparam.type,
            dbapitype,
        )

Beispiel 2 - Entfernen aller Bindungen zu CLOB

Der CLOB-Datentyp in cx_Oracle verursacht einen erheblichen Leistungsaufwand, wird jedoch standardmäßig für den Text-Typ in der SQLAlchemy 1.2-Serie gesetzt. Diese Einstellung kann wie folgt geändert werden:

from sqlalchemy import create_engine, event
from cx_Oracle import CLOB

engine = create_engine("oracle+cx_oracle://scott:tiger@host/xe")


@event.listens_for(engine, "do_setinputsizes")
def _remove_clob(inputsizes, cursor, statement, parameters, context):
    for bindparam, dbapitype in list(inputsizes.items()):
        if dbapitype is CLOB:
            del inputsizes[bindparam]

LOB-Datentypen

LOB-Datentypen beziehen sich auf "Large Object"-Datentypen wie CLOB, NCLOB und BLOB. Moderne Versionen von cx_Oracle sind für diese Datentypen optimiert, um als ein einzelner Puffer geliefert zu werden. Daher verwendet SQLAlchemy standardmäßig diese neueren Typ-Handler.

Um die Verwendung neuerer Typ-Handler zu deaktivieren und LOB-Objekte als klassische gepufferte Objekte mit einer read()-Methode zu liefern, kann der Parameter auto_convert_lobs=False an create_engine() übergeben werden, was nur engine-weit geschieht.

RETURNING-Unterstützung

Der cx_Oracle-Dialekt implementiert RETURNING über OUT-Parameter. Der Dialekt unterstützt RETURNING vollständig.

Zwei-Phasen-Transaktionen werden nicht unterstützt

Zwei-Phasen-Transaktionen werden unter cx_Oracle **nicht unterstützt**, da die Treiberunterstützung hierfür schlecht ist. Der neuere python-oracledb-Dialekt **unterstützt** jedoch Zwei-Phasen-Transaktionen.

Präzisions-Numeriken

SQLAlchemy-numerische Typen können Werte als Python Decimal-Objekte oder Float-Objekte empfangen und zurückgeben. Wenn ein Numeric-Objekt oder eine Unterklasse wie Float, DOUBLE_PRECISION usw. verwendet wird, bestimmt das Flag Numeric.asdecimal, ob Werte bei der Rückgabe zu Decimal konvertiert oder als Float-Objekte zurückgegeben werden sollen. Um die Sache unter Oracle Database zu erschweren, kann der NUMBER-Typ auch Ganzzahlen darstellen, wenn die „Skala“ Null ist. Der Oracle-spezifische Typ NUMBER berücksichtigt dies ebenfalls.

Der cx_Oracle-Dialekt verwendet umfassend auf Verbindungs- und Cursor-Ebene aufrufbare "outputtypehandler", um numerische Werte nach Bedarf umzuwandeln. Diese Aufrufbaren sind spezifisch für die jeweilige Art von Numeric, die verwendet wird, sowie wenn keine SQLAlchemy-Typobjekte vorhanden sind. Es gibt beobachtete Szenarien, in denen die Oracle-Datenbank unvollständige oder mehrdeutige Informationen über die zurückgegebenen numerischen Typen sendet, z. B. eine Abfrage, bei der die numerischen Typen unter mehreren Ebenen von Unterabfragen verborgen sind. Die Typ-Handler tun ihr Bestes, um in allen Fällen die richtige Entscheidung zu treffen, und greifen auf den zugrunde liegenden cx_Oracle DBAPI für all jene Fälle zurück, in denen der Treiber die beste Entscheidung treffen kann.

Wenn keine Typobjekte vorhanden sind, wie bei der Ausführung von reinen SQL-Zeichenketten, ist ein Standard-„outputtypehandler“ vorhanden, der im Allgemeinen numerische Werte zurückgibt, die Präzision und Skala als Python Decimal-Objekte angeben. Um diese Konvertierung nach Decimal aus Leistungsgründen zu deaktivieren, übergeben Sie das Flag coerce_to_decimal=False an create_engine()

engine = create_engine("oracle+cx_oracle://dsn", coerce_to_decimal=False)

Das Flag coerce_to_decimal beeinflusst nur die Ergebnisse von reinen SQL-Zeichenkettenanweisungen, die nicht anderweitig mit einem Numeric SQLAlchemy-Typ (oder einer Unterklasse davon) verknüpft sind.

Geändert in Version 1.2: Das System zur Behandlung von numerischen Werten für cx_Oracle wurde überarbeitet, um neuere cx_Oracle-Funktionen sowie eine bessere Integration von outputtypehandlern zu nutzen.