--Utilisation d'Oracle Cloud
Bien sûr, les types de données sont différents entre Oracle Database et Python. Dans cet article, j'expliquerai comment cx_Oracle sert d'intermédiaire entre les deux types de données.
Quels types de données dans la base de données Oracle sont finalement mappés vers quels types de données Python sont résumés dans le manuel cx_Oracle sous forme de tableau (https://cx-oracle.readthedocs.io/). fr / latest / user_guide / sql_execution.html # fetch-data-types). Comme vous pouvez le voir dans la table liée, les données obtenues à partir de la base de données Oracle sont une fois converties en données du type de données cx_Oracle et stockées dans le type de données Python via le type de données cx_Oracle. Le flux est l'inverse pour les données mises à jour. Voici la correspondance des principaux types de données. Voir le manuel ci-dessus pour une liste complète.
Type de données Oracle Database | cx_Type de données Oracle | Type de données Python |
---|---|---|
CHAR | cx_Oracle.FIXED_CHAR | str |
VARCHAR2 | cx_Oracle.STRING | str |
NUMBER | cx_Oracle.NUMBER | float ou int |
DATE | cx_Oracle.DATETIME | datetime.datetime |
TIMESTAMP | cx_Oracle.TIMESTAMP | datetime.datetime |
RAW | cx_Oracle.BINARY | bytes |
Il convient de noter ici qu'il existe deux types de types de données Python qui prennent en charge le type NUMBER: float et int. Cela dépend de la définition du type NUMBER et de la valeur stockée. Vérifiez le résultat de l'exécution de l'exemple d'application ci-dessous.
sample06a.py
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" pour NUMBER: {type(row[0])}")
print(f""7" en NUMBER.0」 : {type(row[1])}")
print(f""7" en NUMBER.1」 : {type(row[2])}")
print(f"NUMBER(5, 0)Vers "7": {type(row[3])}")
print(f"NUMBER(5, 0)Vers "7.0」 : {type(row[4])}")
print(f"NUMBER(5, 2)Vers "7": {type(row[5])}")
print(f"NUMBER(5, 2)Vers "7.0」 : {type(row[6])}")
print(f"NUMBER(5, 2)Vers "7.1」 : {type(row[7])}")
Résultat d'exécution
$ python sample06a.py
"7" pour NUMBER: <class 'int'>
"7" en NUMBER.0」 : <class 'int'>
"7" en NUMBER.1」 : <class 'float'>
NUMBER(5, 0)Vers "7": <class 'int'>
NUMBER(5, 0)Vers "7.0」 : <class 'int'>
NUMBER(5, 2)Vers "7": <class 'float'>
NUMBER(5, 2)Vers "7.0」 : <class 'float'>
NUMBER(5, 2)Vers "7.1」 : <class 'float'>
À partir du résultat de l'exécution, les règles suivantes peuvent être vues.
Il n'y a pas de problème particulier avec le type int, mais le problème est le type float. Pour les applications métier où Oracle Database est souvent utilisé, il est à craindre que des erreurs d'arrondi puissent se produire et causer des problèmes, en particulier lorsqu'il s'agit d'informations sur l'argent et les fractions flottantes. Dans de tels cas, Python utilise le module décimal pour le gérer, mais cx_Oracle lui-même ne se convertit pas en décimal, comme indiqué dans le tableau ci-dessus. Cependant, cx_Oracle fournit de tels cas.
outputtypehandler Pour les raisons mentionnées ci-dessus, si vous ne souhaitez pas utiliser la spécification de conversion du type de données par défaut de cx_Oracle, si vous spécifiez votre propre fonction de conversion de données dans l'attribut outputtypehandler de l'objet Connection, cette fonction sera convertie à la place de la règle de conversion d'origine. Sera utilisé. Dans le cas de la direction Python → Oracle, il s'agit de l'attribut inputtypehandler.
sample06b.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.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"Aucun gestionnaire de type de sortie")
print(f"Définissez NUMBER sur «7» et tripler: {row[0] * 3}")
print(f""7" en NUMBER.1 "est défini et triplé: {row[2] * 3}")
with connection.cursor() as cursor:
cursor.outputtypehandler = num2Dec
row = cursor.execute(SQL).fetchone()
print(f"Avec le gestionnaire de type de sortie")
print(f"Définissez NUMBER sur «7» et tripler: {row[0] * 3}")
print(f""7" en NUMBER.1 "est défini et triplé: {row[2] * 3}")
Veuillez noter que ce script SELECTs la table et les données créées dans le script précédent. La fonction num2Dec au milieu du script est la nouvelle routine de conversion de données. En définissant la fonction num2Dec comme gestionnaire de type de sortie sur la 5ème ligne à partir du bas, cette fonction fonctionnera. Vous pouvez spécifier n'importe quel nom de fonction et nom d'argument du gestionnaire de type de sortie, mais la spécification de l'argument est définie comme suit, et les 6 sont obligatoires comme arguments même s'ils ne sont pas utilisés dans la fonction.
Ordre des arguments | sens |
---|---|
1 | Objet curseur à utiliser |
2 | Nom de colonne |
3 | Colonne cx_Type de données Oracle |
4 | Taille de la colonne |
5 | Nombre de chiffres fractionnaires dans la colonne(NUMBER(p,s)S) |
6 | Nombre total de chiffres dans la colonne(NUMBER(p,s)P) |
La méthode var de l'objet Cursor dans l'exemple est une méthode qui met à jour les informations de variable pour la variable dans la colonne correspondante sous la forme spécifiée par l'argument. Dans le premier argument, spécifiez le type de données à modifier. Doit être spécifié. La méthode var elle-même est une méthode largement utilisée à des fins autres que outputtypehandler, et le deuxième argument et les suivants sont facultatifs en tant que spécification de méthode, mais pour l'utilisation du outputtypehandler, un paramètre appelé arraysize est requis et la taille du tableau de l'objet Cursor est définie. Doit être réglé.
Résultat d'exécution
$ python sample06b.py
Aucun gestionnaire de type de sortie
Définissez NUMBER sur «7» et tripler: 21
"7" en NUMBER.1 "est défini et triplé: 21.299999999999997
Avec le gestionnaire de type de sortie
Définissez NUMBER sur «7» et tripler: 21
"7" en NUMBER.1 "est défini et triplé: 21.3
Si vous passez par le gestionnaire de type de sortie comme le résultat de l'exécution, le résultat du calcul sera plus attendu. Bien sûr, au lieu d'utiliser le outputtypehandler, vous pouvez le recevoir dans une variable de type float Python, puis le convertir en décimal, mais si vous avez un grand nombre de colonnes prises en charge, vous pouvez facilement coder en utilisant le outputtypehandler.
Recommended Posts