--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.
Quel type de données de la base de données Oracle est finalement mappé à quel type de données Python peut être trouvé dans le manuel cx_Oracle (https://cx-oracle.readthedocs.io/en/latest/user_guide/sql_execution.html). Il est résumé dans # fetch-data-types). Échange de types de données entre Oracle Database et Python Type de données Oracle Database ⇔ Type de données cx_Oracle ⇔ Type de données Python Il sera converti via le flux. Fondamentalement, il existe un type de données cx_Oracle avec un nom commençant par "DB_TYPE_" qui correspond à un certain type de données Oracle Database. Le type de données cx_Oracle qui était utilisé jusqu'à cx_Oracle 7.3 (avant 8) peut toujours être utilisé comme synonim, mais comme il sera obsolète à l'avenir, lors de la création d'une nouvelle application avec la version 8 ou de l'utilisation du type de données cx_Oracle Si des révisions doivent être effectuées, essayez d'utiliser le type de données cx_Oracle qui commence par "DB_TYPE_". En outre, les types de données définis dans l'API DB continueront d'être pris en charge.
■ Mappage des types de données
Type de données Oracle Database | cx_Type de données Oracle | Type de données Python |
---|---|---|
CHA | cx_Oracle.DB_TYPE_CHAR | str |
VARCHAR2 | cx_Oracle.DB_TYPE_VARCHAR | str |
NUMBER | cx_Oracle.DB_TYPE_NUMBER | float ou int |
DATE | cx_Oracle.DB_TYPE_DATE | datetime.datetime |
TIMESTAMP | cx_Oracle.DB_TYPE_TIMESTAMP | datetime.datetime |
RAW | cx_Oracle.DB_TYPE_RAW | bytes |
■ Mappage de type de données conforme à DB API
Type de données Oracle Database | cx_Type de données Oracle | Type de données Python |
---|---|---|
CHAR, 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 |
■ Référence du manuel Type de données cx_Oracle conforme à l'API DB type de données propriétaire cx_Oracle
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(Republier)
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.
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"Aucun OutputTypeHandler")
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 OutputTypeHandler")
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 sample09a.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