Natürlich unterscheiden sich die Datentypen zwischen Oracle Database und Python. In diesem Artikel werde ich erklären, wie cx_Oracle zwischen den beiden Datentypen vermittelt.
Welcher Datentyp der Oracle-Datenbank letztendlich welchem Python-Datentyp zugeordnet ist, finden Sie im Handbuch cx_Oracle (https://cx-oracle.readthedocs.io/en/latest/user_guide/sql_execution.html). Es ist in # fetch-data-types zusammengefasst. Datentypaustausch zwischen Oracle Database und Python Oracle Database-Datentyp ⇔ cx_Oracle-Datentyp ⇔ Python-Datentyp Es wird durch den Fluss umgewandelt. Grundsätzlich gibt es einen cx_Oracle-Datentyp mit einem Namen, der mit "DB_TYPE_" beginnt und einem bestimmten Oracle Database-Datentyp entspricht. Der Datentyp cx_Oracle, der bis cx_Oracle 7.3 (vor 8) verwendet wurde, kann weiterhin als Synonim verwendet werden. Da er jedoch in Zukunft veraltet sein wird, wenn eine neue Anwendung mit Version 8 erstellt oder der Datentyp cx_Oracle verwendet wird Wenn Änderungen vorgenommen werden müssen, stellen Sie sicher, dass Sie den Datentyp cx_Oracle verwenden, der mit "DB_TYPE_" beginnt. Darüber hinaus werden in der DB-API definierte Datentypen weiterhin unterstützt.
■ Datentypzuordnung
Oracle Database-Datentyp | cx_Oracle-Datentyp | Python-Datentyp |
---|---|---|
CHA | cx_Oracle.DB_TYPE_CHAR | str |
VARCHAR2 | cx_Oracle.DB_TYPE_VARCHAR | str |
NUMBER | cx_Oracle.DB_TYPE_NUMBER | float oder int |
DATE | cx_Oracle.DB_TYPE_DATE | datetime.datetime |
TIMESTAMP | cx_Oracle.DB_TYPE_TIMESTAMP | datetime.datetime |
RAW | cx_Oracle.DB_TYPE_RAW | bytes |
■ Datentypzuordnung, die der [DB-API] entspricht (https://www.python.org/dev/peps/pep-0249/)
Oracle Database-Datentyp | cx_Oracle-Datentyp | Python-Datentyp |
---|---|---|
CHAR, VARCHAR2 | cx_Oracle.STRING | str |
NUMBER | cx_Oracle.NUMBER | float oder int |
DATE | cx_Oracle.DATETIME | datetime.datetime |
TIMESTAMP | cx_Oracle.TIMESTAMP | datetime.datetime |
RAW | cx_Oracle.BINARY | bytes |
■ Manuelle Referenz DB API-kompatibler cx_Oracle-Datentyp cx_Oracle's eigener Datentyp
Hierbei ist zu beachten, dass es zwei Arten von Python-Datentypen gibt, die den Typ NUMBER unterstützen: float und int. Dies hängt von der Definition des NUMBER-Typs und dem gespeicherten Wert ab. Überprüfen Sie das Ausführungsergebnis der folgenden Beispielanwendung.
sample06a.py(Erneut veröffentlichen)
import cx_Oracle
USERID = "admin"
PASSWORD = "FooBar"
DESTINATION = "atp1_low"
SQL1 = """
create table sample06a (col1 number, col2 number, col3 number,
col4 number(5, 0), col5 number(5, 0), col6 number(5, 2),
col7 number(5, 2), col8 number(5, 2))
"""
SQL2 = "insert into sample06a values(7, 7.0, 7.1, 7, 7.0, 7, 7.0, 7.1)"
SQL3 = "commit"
SQL4 = "select * from sample06a"
with cx_Oracle.connect(USERID, PASSWORD, DESTINATION) as connection:
with connection.cursor() as cursor:
cursor.execute(SQL1)
cursor.execute(SQL2)
cursor.execute(SQL3)
row = cursor.execute(SQL4).fetchone()
print(f""7" für NUMMER: {type(row[0])}")
print(f""7" in NUMMER.0」 : {type(row[1])}")
print(f""7" in NUMMER.1」 : {type(row[2])}")
print(f"NUMBER(5, 0)Auf "7": {type(row[3])}")
print(f"NUMBER(5, 0)Zu "7.0」 : {type(row[4])}")
print(f"NUMBER(5, 2)Auf "7": {type(row[5])}")
print(f"NUMBER(5, 2)Zu "7.0」 : {type(row[6])}")
print(f"NUMBER(5, 2)Zu "7.1」 : {type(row[7])}")
Ausführungsergebnis
$ python sample06a.py
"7" für NUMMER: <class 'int'>
"7" in NUMMER.0」 : <class 'int'>
"7" in NUMMER.1」 : <class 'float'>
NUMBER(5, 0)Auf "7": <class 'int'>
NUMBER(5, 0)Zu "7.0」 : <class 'int'>
NUMBER(5, 2)Auf "7": <class 'float'>
NUMBER(5, 2)Zu "7.0」 : <class 'float'>
NUMBER(5, 2)Zu "7.1」 : <class 'float'>
Aus dem Ausführungsergebnis sind die folgenden Regeln ersichtlich.
Es gibt kein besonderes Problem mit dem Typ int, aber das Problem ist der Typ float. Bei Geschäftsanwendungen, bei denen häufig Oracle Database verwendet wird, besteht die Sorge, dass Rundungsfehler auftreten und Probleme verursachen können, insbesondere bei Informationen zu Geld und schwebenden Brüchen. In solchen Fällen verwendet Python das Dezimalmodul, um damit umzugehen, aber cx_Oracle selbst konvertiert nicht in Dezimalzahlen, wie in der obigen Tabelle gezeigt. Cx_Oracle sieht jedoch solche Fälle vor.
outputtypehandler Wenn Sie aus den oben genannten Gründen die Konvertierungsspezifikation des Standarddatentyps von cx_Oracle nicht verwenden möchten und Ihre eigene Datenkonvertierungsfunktion im Attribut outputtypehandler des Connection-Objekts angeben, wird diese Funktion anstelle der ursprünglichen Konvertierungsregel konvertiert. Wird verwendet. Im Fall von Python → Oracle ist dies das Attribut inputtypehandler.
sample09a.py
import cx_Oracle
import decimal
USERID = "admin"
PASSWORD = "FooBar"
DESTINATION = "atp1_low"
SQL = "select * from sample06a"
def num2Dec(cursor, name, defaultType, size, precision, scale):
if defaultType == cx_Oracle.DB_TYPE_NUMBER:
return cursor.var(decimal.Decimal, arraysize=cursor.arraysize)
with cx_Oracle.connect(USERID, PASSWORD, DESTINATION) as connection:
with connection.cursor() as cursor:
row = cursor.execute(SQL).fetchone()
print(f"Kein OutputTypeHandler")
print(f"Stellen Sie NUMBER auf "7" und verdreifachen Sie: {row[0] * 3}")
print(f""7" in NUMMER.1 ”wird gesetzt und verdreifacht: {row[2] * 3}")
with connection.cursor() as cursor:
cursor.outputtypehandler = num2Dec
row = cursor.execute(SQL).fetchone()
print(f"Mit OutputTypeHandler")
print(f"Stellen Sie NUMBER auf "7" und verdreifachen Sie: {row[0] * 3}")
print(f""7" in NUMMER.1 ”wird gesetzt und verdreifacht: {row[2] * 3}")
Bitte beachten Sie, dass dieses Skript die Tabelle und die Daten auswählt, die im vorherigen Skript erstellt wurden. Die num2Dec-Funktion in der Mitte des Skripts ist die eigentliche neue Datenkonvertierungsroutine. Wenn Sie die Funktion num2Dec als Ausgabetyphandler in der 5. Zeile von unten festlegen, funktioniert diese Funktion. Sie können einen beliebigen Funktionsnamen und Argumentnamen des Ausgabetyphandlers angeben. Die Angabe des Arguments ist jedoch wie folgt definiert, und alle 6 sind als Argumente erforderlich, auch wenn sie nicht in der Funktion verwendet werden.
Argumentreihenfolge | Bedeutung |
---|---|
1 | Zu bedienendes Cursorobjekt |
2 | Spaltenname |
3 | Spalte cx_Oracle-Datentyp |
4 | Spaltengröße |
5 | Anzahl der Bruchstellen in der Spalte(NUMBER(p,s)S.) |
6 | Gesamtzahl der Stellen in der Spalte(NUMBER(p,s)P.) |
Die var-Methode des Cursor-Objekts im Beispiel ist eine Methode, die die Variableninformationen für die Variable in der entsprechenden Spalte auf die durch das Argument angegebene Form aktualisiert. Geben Sie im ersten Argument den zu ändernden Datentyp an. Muss angegeben werden. Die var-Methode selbst ist eine Methode, die häufig für andere Zwecke als den Ausgabetyphandler verwendet wird. Das zweite und die nachfolgenden Argumente sind als Methodenspezifikation optional. Für die Verwendung des Ausgabetyphandlers ist jedoch ein Parameter namens arraysize erforderlich, und die Arraysize des Cursorobjekts wird festgelegt. Muss eingestellt werden.
Ausführungsergebnis
$ python sample09a.py
Kein Handler für Ausgabetypen
Stellen Sie NUMBER auf "7" und verdreifachen Sie: 21
"7" in NUMMER.1 ”wird gesetzt und verdreifacht: 21.299999999999997
Mit Ausgabetyp-Handler
Stellen Sie NUMBER auf "7" und verdreifachen Sie: 21
"7" in NUMMER.1 ”wird gesetzt und verdreifacht: 21.3
Wenn Sie den Ausgabetyphandler wie das Ausführungsergebnis durchlaufen, wird das Berechnungsergebnis eher erwartet. Anstatt den Ausgabetyphandler zu verwenden, können Sie ihn natürlich in einer Python-Float-Typvariablen empfangen und dann in eine Dezimalzahl konvertieren. Wenn Sie jedoch eine große Anzahl unterstützter Spalten haben, können Sie den Ausgabetyphandler problemlos codieren.
Recommended Posts