将 Oracle 数据类型转换为 SQLAlchemy 类型

Convert Oracle Datatypes to SQLAlchemy Types

我有一个 oracle 数据类型列表(数百个),我想以编程方式将其映射到 SQLAlchemy 数据类型。

一些示例 oracle 数据类型(以及许多其他数据类型)是:

XMLTYPE
VARCHAR2
UROWID
URITYPE
UNDEFINED
TIMESTAMP(9)

我正在将 oracle 中的数据查询到 pandas 数据帧中,然后使用 sql alchemy 将该数据加载到另一个系统。但是我需要指定目标系统中的目标数据类型。 (由于 ETL 过程被批处理,仅使用数据框默认值不起作用;第一批值可能会“误导”数据类型。)

Here 是 SQLAlchemy 数据类型的列表,我需要将 oracle 数据类型映射到 sqlalchemy 数据类型。除了手动构建这样的字典之外,还有其他优雅的方法吗?

编辑:我给出的具体示例数据类型并不重要。我宁愿以编程方式和动态地将 Oracle 中的任意列分配给正确的 SQLAlchemy 数据类型。数据类型是对

的响应
SELECT
    DISTINCT data_type
FROM
    all_tab_columns;

返回了超过 150 个值。所以我真的更愿意避免手动查找每个文档。

  • XMLTYPE 数据类型有 getStringValgetClobVal 方法(取决于内容的长度),您可以使用它们来提取 XML内容只是一个字符串值,可以使用 sqlalchemy.types.Text(在调用 getClobVal 方法之后)。

  • VARCHAR2 只是一个可变长度的字符串。 Oracle 没有 VARCHAR 数据类型,这是它的等价物(VARCHAR 目前是 VARCHAR2 的同义词)。等价于 sqlalchemy.types.String.

  • UROWID 记录为:

    Each row in a database has an address. However, the rows of some tables have addresses that are not physical or permanent or were not generated by Oracle Database. For example, the row addresses of index-organized tables are stored in index leaves, which can move. Rowids of foreign tables (such as DB2 tables accessed through a gateway) are not standard Oracle rowids.

    Oracle uses universal rowids (urowids) to store the addresses of index-organized and foreign tables. Index-organized tables have logical urowids and foreign tables have foreign urowids. Both types of urowid are stored in the ROWID pseudocolumn (as are the physical rowids of heap-organized tables).

    在数据库外持久化一个 UROWID 是没有意义的,因为它代表的数据可能不是永久的,可能会移动,即使它不移动,它也只是代表一个内存位置,而不是任何实际数据。

  • URITYPE 表示 URI 到另一个资源,您可以使用它的 getURL 方法来获取它代表的 URI,应该只是一个字符串值。等效的数据类型为 sqlalchemy.types.Stringsqlalchemy.types.Text(在调用 getURL 方法以获取字符串表示之后)。

  • UNDEFINED 不是数据类型。您应该检查是否有人创建了名为 UNDEFINED.

    的用户定义类型
  • TIMESTAMP(9) 只是一个 TIMESTAMP,精度为 9 十进制秒数。从文档中,您似乎想要 sqlalchemy.dialects.oracle.DATE.


The datatypes are the response to

SELECT DISTINCT data_type FROM all_tab_columns;

请不要依赖此列表,因为它包括 *SYS 模式的表中使用的所有数据类型,您不应接触其中的大部分表,因为更改它们可能会产生无法预料的后果(包括使你的数据库无法使用)。

这些数据类型中的大多数将成为数据库内部工作中使用的私有数据类型;您可以确定它们,因为它们通常在类型名称中有一个 $。下一个最常见的分组是 SDO 几何数据类型,它们都有 SDO_ 前缀。

因此,如果您的查询变为:

SELECT CASE
       WHEN data_type LIKE '%$%' THEN 'Private Type'
       WHEN data_type LIKE 'SDO_%' THEN 'SDO Geometry Type'
       ELSE data_type
       END AS data_type,
       COUNT( DISTINCT data_type ) AS num_instances
FROM   all_tab_columns
GROUP BY
       CASE
       WHEN data_type LIKE '%$%' THEN 'Private Type'
       WHEN data_type LIKE 'SDO_%' THEN 'SDO Geometry Type'
       ELSE data_type
       END
ORDER BY num_instances DESC, data_type ASC;

然后,在 db<>fiddle 上,您将获得此输出,用户生成的表为零(因此仅针对系统生成的表):

DATA_TYPE                    | NUM_INSTANCES
:--------------------------- | ------------:
Private Type                 |           130
SDO Geometry Type            |             5
ANYDATA                      |             1
BINARY_DOUBLE                |             1
BLOB                         |             1
CHAR                         |             1
CLOB                         |             1
DATE                         |             1
DS_VARRAY_4_CLOB             |             1
FLOAT                        |             1
HSBLKNAMLST                  |             1
HSBLKVALARY                  |             1
INTERVAL DAY(3) TO SECOND(0) |             1
INTERVAL DAY(3) TO SECOND(2) |             1
INTERVAL DAY(9) TO SECOND(6) |             1
LONG                         |             1
LONG RAW                     |             1
NUMBER                       |             1
NVARCHAR2                    |             1
RAW                          |             1
ROWID                        |             1
TIMESTAMP(0)                 |             1
TIMESTAMP(3)                 |             1
TIMESTAMP(6)                 |             1
TIMESTAMP(6) WITH TIME ZONE  |             1
TIMESTAMP(9)                 |             1
UNDEFINED                    |             1
VARCHAR2                     |             1
XMLTYPE                      |             1

162 种数据类型中有 130 种是私有的,另外 5 种是 SDO 几何类型。

调查其他“有趣的类型”:

SELECT owner, table_name, column_name, data_type
FROM   ALL_TAB_COLUMNS
WHERE  data_type IN ( 'UNDEFINED', 'HSBLKVALARY', 'HSBLKNAMLST', 'ROWID', 'ANYDATA', 'DS_VARRAY_4_CLOB' )
ORDER BY owner, table_name, data_type

输出:

OWNER  | TABLE_NAME                    | COLUMN_NAME           | DATA_TYPE       
:----- | :---------------------------- | :-------------------- | :---------------
CTXSYS | CTX_USER_PENDING              | PND_ROWID             | ROWID           
CTXSYS | DRV$PENDING                   | PND_ROWID             | ROWID           
CTXSYS | DRV$UNINDEXED                 | UNX_ROWID             | ROWID           
CTXSYS | DRV$UNINDEXED2                | UNX_ROWID             | ROWID           
CTXSYS | DRV$WAITING                   | WTG_ROWID             | ROWID           
MDSYS  | SDO_GR_MOSAIC_0               | RID                   | ROWID           
MDSYS  | SDO_GR_MOSAIC_1               | RID                   | ROWID           
MDSYS  | SDO_GR_MOSAIC_2               | RID                   | ROWID           
SYS    | ALL_SCHEDULER_JOB_ARGS        | ANYDATA_VALUE         | ANYDATA         
SYS    | ALL_SCHEDULER_PROGRAM_ARGS    | DEFAULT_ANYDATA_VALUE | ANYDATA         
SYS    | ALL_SQLSET_BINDS              | VALUE                 | ANYDATA         
SYS    | ALL_STREAMS_MESSAGE_CONSUMERS | NOTIFICATION_CONTEXT  | ANYDATA         
SYS    | ALL_SUMDELTA                  | HIGHROWID             | ROWID           
SYS    | ALL_SUMDELTA                  | LOWROWID              | ROWID           
SYS    | HS$_PARALLEL_METADATA         | PARTITION_COL_TYPES   | HSBLKNAMLST     
SYS    | HS$_PARALLEL_METADATA         | PARTITION_COL_NAMES   | HSBLKNAMLST     
SYS    | HS_PARALLEL_METADATA          | PARTITION_COL_NAMES   | HSBLKNAMLST     
SYS    | HS_PARALLEL_METADATA          | PARTITION_COL_TYPES   | HSBLKNAMLST     
SYS    | HS_PARALLEL_PARTITION_DATA    | PARTITION_COL_TYPES   | HSBLKNAMLST     
SYS    | HS_PARALLEL_PARTITION_DATA    | PARTITION_COL_NAMES   | HSBLKNAMLST     
SYS    | HS_PARALLEL_PARTITION_DATA    | HIGH_VALUE            | HSBLKVALARY     
SYS    | HS_PARALLEL_PARTITION_DATA    | LOW_VALUE             | HSBLKVALARY     
SYS    | ORA_KGLR7_IDL_SB4             | PIECE                 | UNDEFINED       
SYS    | ORA_KGLR7_IDL_UB2             | PIECE                 | UNDEFINED       
SYS    | USER_COMPARISON_ROW_DIF       | LOCAL_ROWID           | ROWID           
SYS    | USER_COMPARISON_ROW_DIF       | REMOTE_ROWID          | ROWID           
SYS    | USER_PARALLEL_EXECUTE_CHUNKS  | END_ROWID             | ROWID           
SYS    | USER_PARALLEL_EXECUTE_CHUNKS  | START_ROWID           | ROWID           
SYS    | USER_SCHEDULER_JOB_ARGS       | ANYDATA_VALUE         | ANYDATA         
SYS    | USER_SCHEDULER_PROGRAM_ARGS   | DEFAULT_ANYDATA_VALUE | ANYDATA         
SYS    | USER_SQLSET_BINDS             | VALUE                 | ANYDATA         
SYS    | USER_SQLTUNE_BINDS            | VALUE                 | ANYDATA         
SYS    | USER_SR_STLOG_EXCEPTIONS      | BAD_ROWID             | ROWID           
SYS    | USER_SUBSCR_REGISTRATIONS     | ANY_CONTEXT           | ANYDATA         
SYS    | _USER_COMPARISON_ROW_DIF      | RMT_ROWID             | ROWID           
SYS    | _USER_COMPARISON_ROW_DIF      | LOC_ROWID             | ROWID           
SYS    | _user_stat_varray             | CL1                   | DS_VARRAY_4_CLOB
XDB    | XDB$ROOT_INFO_V               | RESOURCE_ROOT         | ROWID           

这些都是 *SYS 表或私有表,您几乎肯定永远不会想直接与它们交互。

UNDEFINED 类型很有趣,因为它似乎未定义:

SELECT owner, type_name
FROM   ALL_TYPES
WHERE  TYPE_NAME = 'UNDEFINED';

Returns 零行和:

CREATE TABLE TABLE_NAME ( id UNDEFINED );

引发异常 ORA-00902: invalid datatype


如何更好地确定您正在使用的类型?只需查看您创建的架构:

SELECT DISTINCT owner, data_type
FROM   all_tab_columns
WHERE  owner IN ( 'USER1', 'USER2', 'USER3' )

那么您就知道这些数据类型是您的用户创建的表中使用的数据类型。您应该发现,除非您正在做一些深奥的事情,否则您使用的大多数(如果不是全部)类型将由 SQLAlchemy 本机处理。

db<>fiddle here