Oracle

对 Oracle 数据库的支持。

下表总结了当前对数据库版本的支持级别。

支持的 Oracle 版本

支持类型

版本

支持的版本

11+

尽力而为

9+

DBAPI 支持

以下方言/DBAPI 选项可用。有关连接信息,请参阅各个 DBAPI 部分。

自动递增行为

包含整数主键的 SQLAlchemy 表对象通常被认为具有“自动递增”行为,这意味着它们可以在 INSERT 时生成自己的主键值。在 Oracle 中使用时,有两种选择可用,即使用 IDENTITY 列(仅限 Oracle 12 及更高版本)或将 SEQUENCE 与列关联。

指定 GENERATED AS IDENTITY(Oracle 12 及更高版本)

从版本 12 开始,Oracle 可以使用 IDENTITY 列,使用 Identity 指定自动递增行为

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

上面 Table 对象的 CREATE TABLE 将是

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

Identity 对象支持许多选项来控制列的“自动递增”行为,例如起始值、递增值等。除了标准选项外,Oracle 还支持将 Identity.always 设置为 None 以使用默认生成的模式,在 DDL 中呈现 GENERATED AS IDENTITY。它还支持将 Identity.on_null 设置为 True 以指定 ON NULL 与 'BY DEFAULT' IDENTITY 列一起使用。

使用 SEQUENCE(所有 Oracle 版本)

旧版本的 Oracle 没有“自动递增”功能,SQLAlchemy 依赖于序列来生成这些值。在旧版本的 Oracle 中,必须始终显式指定序列才能启用自动递增。这与大多数假设使用支持自动递增的数据库的文档示例有所不同。要指定序列,请使用 sqlalchemy.schema.Sequence 对象,该对象传递给 Column 构造函数

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

使用表反射时,此步骤也是必需的,即 autoload_with=engine

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

版本 1.4 中的更改: 添加了 IdentityColumn 中构建以指定自动递增列的选项。

事务隔离级别/自动提交

Oracle 数据库支持“READ COMMITTED”和“SERIALIZABLE”隔离模式。cx_Oracle 方言还支持 AUTOCOMMIT 隔离级别。

要使用每个连接执行选项设置

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

对于 READ COMMITTEDSERIALIZABLE,Oracle 方言使用 ALTER SESSION 在会话级别设置级别,该级别在连接返回到连接池时恢复到其默认设置。

有效值 isolation_level 包括

  • READ COMMITTED

  • AUTOCOMMIT

  • SERIALIZABLE

注意

Oracle 方言实现的 Connection.get_isolation_level() 方法必然会强制使用 Oracle LOCAL_TRANSACTION_ID 函数启动事务;否则通常无法读取任何级别。

此外,如果由于权限或其他原因 v$transaction 视图不可用,Connection.get_isolation_level() 方法将引发异常,这在 Oracle 安装中很常见。

cx_Oracle 方言在方言首次连接到数据库时尝试调用 Connection.get_isolation_level() 方法以获取“默认”隔离级别。此默认级别是必需的,以便在使用 Connection.execution_options() 方法临时修改连接后,可以将级别重置回连接。

Connection.get_isolation_level() 方法由于 v$transaction 不可读以及任何其他与数据库相关的故障而引发异常的常见情况下,假设级别为“READ COMMITTED”。对于此初始首次连接条件,不会发出任何警告,因为预计这会在 Oracle 数据库中是常见的限制。

版本 1.3.16 中的新增功能: 为 cx_oracle 方言以及默认隔离级别的概念添加了对 AUTOCOMMIT 的支持

版本 1.3.21 中的新增功能: 添加了对 SERIALIZABLE 的支持以及隔离级别的实时读取。

版本 1.3.22 中的更改: 如果由于 Oracle 安装中 v$transaction 的权限问题导致无法读取默认隔离级别,则默认隔离级别将硬编码为“READ COMMITTED”,这是 1.3.21 之前的行为。

另请参阅

设置事务隔离级别,包括 DBAPI 自动提交

标识符大小写

在 Oracle 中,数据字典使用大写文本表示所有不区分大小写的标识符名称。另一方面,SQLAlchemy 认为所有小写标识符名称不区分大小写。Oracle 方言在进行模式级别通信(例如表的反射和索引)时,会将所有不区分大小写的标识符转换为这两种格式。在 SQLAlchemy 侧使用大写名称表示区分大小写的标识符,SQLAlchemy 将引用该名称 - 这会导致与从 Oracle 收到的数据字典数据不匹配,因此,除非标识符名称真正创建为区分大小写(即使用引用的名称),否则应该在 SQLAlchemy 侧使用所有小写名称。

最大标识符长度

为了帮助进行此更改和其他更改,Oracle 引入了“兼容性”版本的概念,它是一个独立于实际服务器版本的版本号,用于帮助迁移 Oracle 数据库,并且可以在 Oracle 服务器本身内配置。此兼容性版本使用以下查询检索:SELECT value FROM v$parameter WHERE name = 'compatible';。SQLAlchemy Oracle 方言在确定默认最大标识符长度时,会尝试在首次连接时使用此查询来确定服务器的有效兼容性版本,该版本决定了服务器允许的最大标识符长度。如果该表不可用,则会使用服务器版本信息。

从 SQLAlchemy 1.4 开始,Oracle 方言的默认最大标识符长度为 128 个字符。首次连接时,将检测兼容性版本,如果它小于 Oracle 版本 12.2,则最大标识符长度将更改为 30 个字符。在所有情况下,设置 create_engine.max_identifier_length 参数将绕过此更改,并且将使用给定的值。

engine = create_engine(
    "oracle+cx_oracle://scott:tiger@oracle122",
    max_identifier_length=30)

最大标识符长度在生成匿名 SQL 标签时发挥作用,但更重要的是在根据命名约定生成约束名称时发挥作用。正是这一方面导致 SQLAlchemy 需要保守地更改此默认值。例如,以下命名约定根据标识符长度产生两个截然不同的约束名称

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))

标识符长度为 30 时,上面的 CREATE INDEX 如下所示

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

但是,长度为 128 时,它将变为

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)

因此,在 Oracle 服务器版本 12.2 或更高版本上运行过 SQLAlchemy 1.4 之前的版本的应用程序,可能会遇到数据库迁移想要在以前使用较短长度生成的名称上“DROP CONSTRAINT”的情况。当在调整索引或约束名称之前更改标识符长度时,此迁移将失败。强烈建议此类应用程序使用 create_engine.max_identifier_length 来控制截断名称的生成,并在更改此值时,在暂存环境中完全审查和测试所有数据库迁移,以确保已缓解此更改的影响。

1.4 版中的变更: Oracle 的默认 max_identifier_length 为 128 个字符,如果检测到旧版本的 Oracle 服务器(兼容性版本 < 12.2),则在首次连接时将其调整为 30 个字符。

LIMIT/OFFSET/FETCH 支持

Select.limit()Select.offset() 这样的方法使用 FETCH FIRST N ROW / OFFSET N ROWS 语法,假设 Oracle 12c 或更高版本,并假设 SELECT 语句没有嵌入在 UNION 等复合语句中。此语法也可以通过使用 Select.fetch() 方法直接获得。

2.0 版中的变更: Oracle 方言现在对所有 Select.limit()Select.offset() 使用(包括 ORM 和旧版 Query)使用 FETCH FIRST N ROW / OFFSET N ROWS。要强制使用使用窗口函数的旧版行为,请将 enable_offset_fetch=False 方言参数指定给 create_engine()

通过将 enable_offset_fetch=False 传递给 create_engine(),可以在任何 Oracle 版本上禁用 FETCH FIRST / OFFSET 的使用,这将强制使用使用窗口函数的“旧版”模式。在使用 Oracle 12c 之前的版本时,此模式也会自动选择。

在使用旧版模式或在复合语句中嵌入具有 limit/offset 的 Select 语句时,将使用基于窗口函数的 LIMIT / OFFSET 的模拟方法,该方法涉及使用 ROW_NUMBER 创建子查询,这容易出现性能问题以及复杂语句的 SQL 构造问题。但是,此方法受所有 Oracle 版本支持。请参阅下面的说明。

有关 LIMIT / OFFSET 模拟的说明(当无法使用 fetch() 方法时)

如果使用 Select.limit()Select.offset(),或在 ORM 中使用 Oracle 12c 之前的版本的 Query.limit()Query.offset() 方法,则以下说明适用

RETURNING 支持

Oracle 数据库完全支持 RETURNING,用于使用单个绑定参数集合调用的 INSERT、UPDATE 和 DELETE 语句(即 cursor.execute() 风格的语句;SQLAlchemy 通常不支持 executemany 语句中的 RETURNING)。也可以返回多行。

2.0 版中的变更: Oracle 后端完全支持与其他后端相同的 RETURNING。

ON UPDATE CASCADE

Oracle 没有原生 ON UPDATE CASCADE 功能。可以从 https://web.archive.org/web/20090317041251/https://asktom.oracle.com/tkyte/update_cascade/index.html 获取基于触发器的解决方案。

在使用 SQLAlchemy ORM 时,ORM 具有有限的能力手动发出级联更新 - 使用“deferrable=True, initially='deferred'”关键字参数指定 ForeignKey 对象,并在每个关系() 上指定“passive_updates=False”。

Oracle 8 兼容性

警告

SQLAlchemy 2.0 不确定 Oracle 8 兼容性的状态。

当检测到 Oracle 8 时,方言会在内部将自身配置为以下行为

  • use_ansi 标志设置为 False。这会将所有 JOIN 短语转换为 WHERE 子句,并且在 LEFT OUTER JOIN 的情况下,会使用 Oracle 的 (+) 运算符。

  • 当使用 Unicode 时,不再将 NVARCHAR2 和 NCLOB 数据类型生成为 DDL - 而是发出 VARCHAR2 和 CLOB。这是因为这些类型似乎在 Oracle 8 上无法正常工作,即使它们可用。 NVARCHARNCLOB 类型将始终生成 NVARCHAR2 和 NCLOB。

约束反射

Oracle 方言可以返回有关外键、唯一键和 CHECK 约束以及表索引的信息。

可以使用 Inspector.get_foreign_keys()Inspector.get_unique_constraints()Inspector.get_check_constraints()Inspector.get_indexes() 获取有关这些约束的原始信息。

在版本 1.2 中更改: Oracle 方言现在可以反射 UNIQUE 和 CHECK 约束。

Table 级别使用反射时,Table 将包括这些约束。

请注意以下注意事项

  • 当使用 Inspector.get_check_constraints() 方法时,Oracle 会为指定“NOT NULL”的列构建一个特殊的“IS NOT NULL”约束。默认情况下,不会返回此约束;要包括“IS NOT NULL”约束,请传递标志 include_all=True

    from sqlalchemy import create_engine, inspect
    
    engine = create_engine("oracle+cx_oracle://s:t@dsn")
    inspector = inspect(engine)
    all_check_constraints = inspector.get_check_constraints(
        "some_table", include_all=True)
  • 在大多数情况下,当反射 Table 时,UNIQUE 约束不会作为 UniqueConstraint 对象可用,因为 Oracle 在大多数情况下会将唯一约束与 UNIQUE 索引镜像(例外情况似乎是当两个或多个唯一约束代表相同的列时);Table 将改为使用带有 unique=True 标志的 Index 表示这些约束。

  • Oracle 为表的主键创建隐式索引;此索引排除在所有索引结果之外。

  • 为索引反映的列列表不包括以 SYS_NC 开头的列名。

具有 SYSTEM/SYSAUX 表空间的表名

方法 Inspector.get_table_names()Inspector.get_temp_table_names() 都为当前引擎返回表名列表。这些方法也是 MetaData.reflect() 等操作中发生的反射的一部分。默认情况下,这些操作会将 SYSTEMSYSAUX 表空间排除在操作之外。要更改此设置,可以在引擎级别使用 exclude_tablespaces 参数更改默认的排除表空间列表。

# exclude SYSAUX and SOME_TABLESPACE, but not SYSTEM
e = create_engine(
  "oracle+cx_oracle://scott:tiger@xe",
  exclude_tablespaces=["SYSAUX", "SOME_TABLESPACE"])

日期时间兼容性

Oracle 没有名为 DATETIME 的数据类型,它只有 DATE,实际上可以存储日期和时间值。因此,Oracle 方言提供了一种类型 DATE,它是 DateTime 的子类。此类型没有特殊行为,只是作为此类型的“标记”存在;此外,当数据库列被反射并且类型被报告为 DATE 时,将使用支持时间的 DATE 类型。

Oracle 表选项

CREATE TABLE 语句在 Oracle 中与 Table 结构一起支持以下选项。

  • 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)
    
    The ``oracle_compress`` parameter accepts either an integer compression
    level, or ``True`` to use the default compression level.
  • TABLESPACE:

    Table('mytable', metadata, ...,
        oracle_tablespace="EXAMPLE_TABLESPACE")
    
    The ``oracle_tablespace`` parameter specifies the tablespace in which the
    table is to be created. This is useful when you want to create a table in a
    tablespace other than the default tablespace of the user.
    
    .. versionadded:: 2.0.37

Oracle 特定的索引选项

位图索引

您可以指定 oracle_bitmap 参数来创建位图索引而不是 B 树索引。

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

位图索引不能是唯一的,也不能被压缩。SQLAlchemy 不会检查此类限制,只有数据库会检查。

索引压缩

Oracle 对于包含大量重复值的索引有更有效的存储模式。使用 oracle_compress 参数来开启键压缩。

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)

参数 oracle_compress 接受一个整数,指定要压缩的前缀列数量,或 True,使用默认值(对于非唯一索引的所有列,对于唯一索引的所有列,除了最后一列)。

Oracle 数据类型

与所有 SQLAlchemy 方言一样,所有已知在 Oracle 中有效的 UPPERCASE 类型都可以从顶级方言导入,无论它们来自 sqlalchemy.types 还是本地方言。

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

在版本 1.2.19 中添加: NCHAR 添加到 Oracle 方言导出的数据类型列表中。

特定于 Oracle 或具有 Oracle 特定构造参数的类型如下所示。

对象名称 描述

BFILE

BINARY_DOUBLE

BINARY_FLOAT

DATE

提供 Oracle DATE 类型。

FLOAT

Oracle FLOAT。

INTERVAL

LONG

NCLOB

NUMBER

NVARCHAR2

NVARCHAR 的别名。

RAW

ROWID

Oracle ROWID 类型。

TIMESTAMP

Oracle 的 TIMESTAMP 实现,支持其他 Oracle 特定模式。

class sqlalchemy.dialects.oracle.BFILE

成员

__init__()

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

sqlalchemy.types.LargeBinary.__init__ 方法继承 LargeBinary

构造 LargeBinary 类型。

参数:

length – 可选,列的长度,用于 DDL 语句,对于那些接受长度的二进制类型,例如 MySQL BLOB 类型。

class sqlalchemy.dialects.oracle.BINARY_DOUBLE

成员

__init__()

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

继承自 sqlalchemy.types.Float.__init__ 方法 Float

构造一个 Float。

参数:
  • precision

    用于 DDL CREATE TABLE 的数值精度。后端**应该**尝试确保此精度表示通用 Float 数据类型的数字位数。

    注意

    对于 Oracle 后端,当渲染 DDL 时,Float.precision 参数不被接受,因为 Oracle 不支持以小数位数指定 float 精度。 相反,使用 Oracle 特定的 FLOAT 数据类型并指定 FLOAT.binary_precision 参数。这是 SQLAlchemy 版本 2.0 中的新功能。

    要创建数据库无关的 Float,它分别为 Oracle 指定二进制精度,请使用 TypeEngine.with_variant(),如下所示

    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 – 与 Numeric 相同的标志,但默认为 False。 请注意,将此标志设置为 True 会导致浮点转换。

  • decimal_return_scale – 从浮点数转换为 Python 十进制数时使用的默认比例。由于小数精度问题,浮点数通常会长得多,大多数浮点数据库类型都没有“比例”的概念,因此默认情况下,float 类型在转换时会寻找前十个小数位。指定此值将覆盖该长度。请注意,MySQL 浮点类型(确实包含“比例”)将使用“比例”作为 decimal_return_scale 的默认值,除非另有指定。

sqlalchemy.dialects.oracle.BINARY_FLOAT

成员

__init__()

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

继承自 sqlalchemy.types.Float.__init__ 方法 Float

构造一个 Float。

参数:
  • precision

    用于 DDL CREATE TABLE 的数值精度。后端**应该**尝试确保此精度表示通用 Float 数据类型的数字位数。

    注意

    对于 Oracle 后端,当渲染 DDL 时,Float.precision 参数不被接受,因为 Oracle 不支持以小数位数指定 float 精度。 相反,使用 Oracle 特定的 FLOAT 数据类型并指定 FLOAT.binary_precision 参数。这是 SQLAlchemy 版本 2.0 中的新功能。

    要创建数据库无关的 Float,它分别为 Oracle 指定二进制精度,请使用 TypeEngine.with_variant(),如下所示

    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 – 与 Numeric 相同的标志,但默认为 False。 请注意,将此标志设置为 True 会导致浮点转换。

  • decimal_return_scale – 从浮点数转换为 Python 十进制数时使用的默认比例。由于小数精度问题,浮点数通常会长得多,大多数浮点数据库类型都没有“比例”的概念,因此默认情况下,float 类型在转换时会寻找前十个小数位。指定此值将覆盖该长度。请注意,MySQL 浮点类型(确实包含“比例”)将使用“比例”作为 decimal_return_scale 的默认值,除非另有指定。

sqlalchemy.dialects.oracle.DATE

提供 Oracle DATE 类型。

此类型没有特殊 Python 行为,除了它继承了 DateTime;这是为了适应 Oracle DATE 类型支持时间值的事实。

成员

__init__()

类签名

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

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

继承自 sqlalchemy.types.DateTime.__init__ 方法 DateTime

构造一个新的 DateTime.

参数:

timezone – 布尔值。指示 datetime 类型是否应该启用时区支持,如果**仅在基础日期/时间保存类型上**可用。建议直接使用 TIMESTAMP 数据类型时使用此标志,因为某些数据库包含与支持时区的 TIMESTAMP 数据类型不同的通用日期/时间保存类型,例如 Oracle。

sqlalchemy.dialects.oracle.FLOAT

Oracle FLOAT。

这与 FLOAT 相同,除了接受 Oracle 特定的 FLOAT.binary_precision 参数,并且 Float.precision 参数不被接受。

Oracle FLOAT 类型以“二进制精度”表示精度,默认为 126。对于 REAL 类型,值为 63。此参数不会干净地映射到特定的小数位数,而是大致相当于所需的小数位数除以 0.3103。

版本 2.0 中的新功能。

成员

__init__()

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

构造一个 FLOAT

参数:
  • binary_precision – 在 DDL 中渲染的 Oracle 二进制精度值。这可以通过公式“十进制精度 = 0.30103 * 二进制精度”近似为十进制字符数。Oracle 为 FLOAT / DOUBLE PRECISION 使用的默认值为 126。

  • asdecimal – 见 Float.asdecimal

  • decimal_return_scale – 见 Float.decimal_return_scale

sqlalchemy.dialects.oracle.INTERVAL

成员

__init__()

类签名

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

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

构造一个 INTERVAL。

注意,目前仅支持 DAY TO SECOND 区间。这是因为在可用的 DBAPI 中不支持 YEAR TO MONTH 区间。

参数:
  • day_precision – 天精度值。这是存储天字段的位数。默认为“2”。

  • second_precision – 秒精度值。这是存储小数秒字段的位数。默认为“6”。

sqlalchemy.dialects.oracle.NCLOB

成员

__init__()

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

sqlalchemy.types.String.__init__ 方法继承 String

创建一个保存字符串的类型。

参数:
  • length – 可选,在 DDL 和 CAST 表达式中使用的列的长度。如果不会发出任何 CREATE TABLE,则可以安全地省略。某些数据库可能需要在 DDL 中使用 length,并在发出 CREATE TABLE DDL 时,如果包含没有长度的 VARCHAR,则会引发异常。值是解释为字节还是字符是特定于数据库的。

  • collation

    可选,在 DDL 和 CAST 表达式中使用的列级排序规则。使用 SQLite、MySQL 和 PostgreSQL 支持的 COLLATE 关键字渲染。例如

    >>> 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

    注意

    在大多数情况下,应该使用 UnicodeUnicodeText 数据类型来表示预期存储非 ASCII 数据的 Column。这些数据类型将确保在数据库上使用正确的类型。

属性 sqlalchemy.dialects.oracle..sqlalchemy.dialects.oracle.NVARCHAR2

NVARCHAR 的别名。

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

成员

__init__()

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

sqlalchemy.types.String.__init__ 方法继承 String

创建一个保存字符串的类型。

参数:
  • length – 可选,用于 DDL 和 CAST 表达式中的列长度。如果不会发出 CREATE TABLE,则可以安全地省略。某些数据库可能需要使用 DDL 中的 length,并在发出 CREATE TABLE DDL 时,如果包含没有长度的 VARCHAR,则会引发异常。该值是解释为字节还是字符取决于数据库。

  • collation

    可选,在 DDL 和 CAST 表达式中使用的列级排序规则。使用 SQLite、MySQL 和 PostgreSQL 支持的 COLLATE 关键字渲染。例如

    >>> 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

    注意

    在大多数情况下,应该使用 UnicodeUnicodeText 数据类型来表示预期存储非 ASCII 数据的 Column。这些数据类型将确保在数据库上使用正确的类型。

class sqlalchemy.dialects.oracle.RAW

类签名

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

class sqlalchemy.dialects.oracle.ROWID

Oracle ROWID 类型。

在 cast() 或类似函数中使用时,会生成 ROWID。

class sqlalchemy.dialects.oracle.TIMESTAMP

Oracle 的 TIMESTAMP 实现,支持其他 Oracle 特定模式。

版本 2.0 中的新功能。

成员

__init__()

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

构造一个新的 TIMESTAMP

参数:
  • timezone – 布尔值。指示 TIMESTAMP 类型应使用 Oracle 的 TIMESTAMP WITH TIME ZONE 数据类型。

  • local_timezone – 布尔值。指示 TIMESTAMP 类型应使用 Oracle 的 TIMESTAMP WITH LOCAL TIME ZONE 数据类型。

cx_Oracle

通过 cx-Oracle 驱动程序支持 Oracle 数据库。

DBAPI

cx-Oracle 的文档和下载信息(如果适用)可在以下位置找到:https://oracle.github.io/python-cx_Oracle/

连接

连接字符串

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

DSN 与主机名连接

cx_Oracle 提供了几种方法来指示目标数据库。方言从一系列不同的 URL 形式进行转换。

使用 Easy Connect 语法的主机名连接

给定目标 Oracle 数据库的主机名、端口和服务名称,例如来自 Oracle 的 Easy Connect 语法,那么在 SQLAlchemy 中使用 service_name 查询字符串参数进行连接。

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

不支持 完整的 Easy Connect 语法。请改用 tnsnames.ora 文件并使用 DSN 进行连接。

使用 tnsnames.ora 或 Oracle Cloud 的连接

或者,如果未提供端口、数据库名称或 service_name,则方言将使用 Oracle DSN“连接字符串”。这将 URL 的“主机名”部分用作数据源名称。例如,如果 tnsnames.ora 文件包含以下 网络服务名称 myalias

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

myalias 是 URL 的主机名部分时,cx_Oracle 方言将连接到该数据库服务,而无需指定端口、数据库名称或 service_name

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

Oracle Cloud 用户应使用此语法并按照 cx_Oracle 文档 连接到自治数据库 中所述配置云钱包。

SID 连接

要使用 Oracle 已过时的 SID 连接语法,可以将 SID 传递到 URL 的“数据库名称”部分,如下所示

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

在上面,传递给 cx_Oracle 的 DSN 是由 cx_Oracle.makedsn() 创建的,如下所示

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

传递 cx_Oracle 连接参数

通常可以通过 URL 查询字符串传递其他连接参数;某些符号(如 cx_Oracle.SYSDBA)会被拦截并转换为正确的符号。

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

在版本 1.3 中更改: cx_oracle 方言现在接受 URL 字符串本身内的所有参数名称,以便传递给 cx_Oracle DBAPI。与以前一样,但未正确记录,create_engine.connect_args 参数也接受所有 cx_Oracle DBAPI 连接参数。

要将参数直接传递给 .connect() 而无需使用查询字符串,请使用 create_engine.connect_args 字典。可以传递任何 cx_Oracle 参数值和/或常量,例如

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
    }
)

请注意,在 cx_Oracle 8.0 中,encodingnencoding 的默认值已更改为“UTF-8”,因此在使用该版本或更高版本时,可以省略这些参数。

SQLAlchemy cx_Oracle 方言在驱动程序之外使用的选项

还有一些由 SQLAlchemy cx_oracle 方言本身使用的选项。这些选项始终直接传递给 create_engine() ,例如

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

cx_oracle 方言接受的参数如下

  • arraysize - 在游标上设置 cx_oracle.arraysize 值;默认为 None,表示应使用驱动程序默认值(通常值为 100)。此设置控制在获取行时缓冲多少行,并在修改时对性能产生重大影响。该设置适用于 cx_Oracleoracledb

    在版本 2.0.26 中更改: - 将默认值从 50 更改为 None,以使用驱动程序本身的默认值。

  • auto_convert_lobs - 默认为 True;请参阅 LOB 数据类型

  • coerce_to_decimal - 请参阅 精度数值 了解详细信息。

  • encoding_errors - 请参阅 编码错误 了解详细信息。

使用 cx_Oracle SessionPool

cx_Oracle 库提供了自己的连接池实现,可以替代 SQLAlchemy 的池功能。这可以通过使用 create_engine.creator 参数提供一个返回新连接的函数来实现,并通过将 create_engine.pool_class 设置为 NullPool 来禁用 SQLAlchemy 的池。

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"
)

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

然后可以照常使用上面的引擎,cx_Oracle 的池会处理连接池。

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

除了为多用户应用程序提供可扩展的解决方案之外,cx_Oracle 会话池还支持某些 Oracle 功能,如 DRCP 和 应用程序连续性

使用 Oracle 数据库驻留连接池 (DRCP)

在使用 Oracle 的 DRCP 时,最佳实践是在从 SessionPool 获取连接时传递连接类和“纯度”。请参阅 cx_Oracle DRCP 文档

可以通过包装 pool.acquire() 来实现。

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)

然后可以正常使用上述引擎,cx_Oracle 处理会话池,Oracle 数据库另外使用 DRCP。

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

Unicode

与 Python 3 下所有 DBAPI 一样,所有字符串本质上都是 Unicode 字符串。然而,在所有情况下,驱动程序都需要显式编码配置。

确保正确的客户端编码

对于几乎所有与 Oracle 相关的软件,建立客户端编码的长期接受的标准是通过 NLS_LANG 环境变量。cx_Oracle 与大多数其他 Oracle 驱动程序一样,将使用此环境变量作为其编码配置的来源。此变量的格式是特有的;典型值将是 AMERICAN_AMERICA.AL32UTF8

cx_Oracle 驱动程序还支持一种编程替代方案,即直接将 encodingnencoding 参数传递到其 .connect() 函数。这些可以存在于 URL 中,如下所示

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

有关 encodingnencoding 参数的含义,请参阅 字符集和国家语言支持 (NLS)

版本 1.3.22 中的更改: 如果由于 Oracle 安装中 v$transaction 的权限问题导致无法读取默认隔离级别,则默认隔离级别将硬编码为“READ COMMITTED”,这是 1.3.21 之前的行为。

字符集和国家语言支持 (NLS) - 在 cx_Oracle 文档中。

特定于 Unicode 的列数据类型

核心表达式语言通过使用 UnicodeUnicodeText 数据类型来处理 Unicode 数据。这些类型默认对应于 VARCHAR2 和 CLOB Oracle 数据类型。在将这些数据类型与 Unicode 数据一起使用时,预计 Oracle 数据库已配置为使用支持 Unicode 的字符集,并且 NLS_LANG 环境变量已正确设置,以便 VARCHAR2 和 CLOB 数据类型可以容纳数据。

如果 Oracle 数据库未配置为使用 Unicode 字符集,则有两种选择:使用 NCHARNCLOB 数据类型,或将标志 use_nchar_for_unicode=True 传递给 create_engine(),这将导致 SQLAlchemy 方言使用 NCHAR/NCLOB 而不是 VARCHAR/CLOB 来表示 Unicode / UnicodeText 数据类型。

在版本 1.3 中更改: UnicodeUnicodeText 数据类型现在对应于 VARCHAR2CLOB Oracle 数据类型,除非将 use_nchar_for_unicode=True 传递给方言,当调用 create_engine() 时。

编码错误

对于 Oracle 数据库中存在编码错误数据的罕见情况,方言接受参数 encoding_errors,该参数将传递给 Unicode 解码函数,以影响处理解码错误的方式。该值最终由 Python decode 函数使用,并通过 cx_Oracle 的 encodingErrors 参数传递,该参数由 Cursor.var() 使用,以及 SQLAlchemy 自己的解码函数,因为 cx_Oracle 方言在不同情况下使用这两种函数。

版本 1.3.11 中的新增功能。

使用 setinputsizes 对 cx_Oracle 数据绑定性能进行细粒度控制

cx_Oracle DBAPI 严重依赖于 DBAPI setinputsizes() 调用的使用。此调用的目的是建立与作为参数传递的 Python 值的 SQL 语句绑定的数据类型。虽然实际上没有其他 DBAPI 将任何用途分配给 setinputsizes() 调用,但 cx_Oracle DBAPI 在其与 Oracle 客户端接口的交互中严重依赖于它,并且在某些情况下,SQLAlchemy 无法准确知道如何绑定数据,因为某些设置会导致截然不同的性能特征,同时会更改类型强制行为。

强烈建议 cx_Oracle 方言的用户通读 cx_Oracle 的内置数据类型符号列表,网址为 https://cx-oracle.readthedocs.io/en/latest/api_manual/module.html#database-types。请注意,在某些情况下,使用这些类型与不使用这些类型相比,可能会导致性能大幅下降,尤其是在指定 cx_Oracle.CLOB 时。

在 SQLAlchemy 方面,DialectEvents.do_setinputsizes() 事件可用于运行时可见性(例如日志记录)以进行 setinputsizes 步骤,以及完全控制如何在每个语句的基础上使用 setinputsizes()

版本 1.2.9 中的新增功能: 添加了 DialectEvents.setinputsizes()

示例 1 - 日志记录所有 setinputsizes 调用

以下示例说明了如何在将中间值转换为原始 setinputsizes() 参数字典之前,从 SQLAlchemy 的角度记录这些值。字典的键是 BindParameter 对象,它们具有 .key.type 属性

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)

示例 2 - 删除所有绑定到 CLOB

cx_Oracle 中的 CLOB 数据类型会产生很大的性能开销,但在 SQLAlchemy 1.2 系列中,默认情况下会为 Text 类型设置此数据类型。此设置可以按如下方式修改

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]

RETURNING 支持

cx_Oracle 方言使用 OUT 参数实现 RETURNING。方言完全支持 RETURNING。

LOB 数据类型

LOB 数据类型是指“大型对象”数据类型,例如 CLOB、NCLOB 和 BLOB。现代版本的 cx_Oracle 和 oracledb 针对这些数据类型进行了优化,以便作为单个缓冲区传递。因此,SQLAlchemy 默认情况下使用这些更新的类型处理程序。

要禁用使用更新的类型处理程序并将 LOB 对象作为具有 read() 方法的经典缓冲对象传递,可以将参数 auto_convert_lobs=False 传递给 create_engine(),这只会发生在整个引擎范围内。

不支持两阶段事务(使用 oracledb)

由于驱动程序支持不佳,cx_Oracle 下**不支持**两阶段事务。但是,更新的 python-oracledb 方言**确实**支持两阶段事务,应优先使用它。

精确数值

SQLAlchemy 的数值类型可以处理接收和返回 Python Decimal 对象或浮点对象的值。当使用 Numeric 对象或其子类,例如 FloatDOUBLE_PRECISION 等时,Numeric.asdecimal 标志决定返回值是否应该在返回时强制转换为 Decimal,还是以浮点对象返回。为了使事情在 Oracle 下更加复杂,Oracle 的 NUMBER 类型也可以表示整数,如果“scale”为零,因此 Oracle 特定的 NUMBER 类型也考虑了这一点。

cx_Oracle 方言广泛使用连接和游标级别的“outputtypehandler”可调用函数来根据需要强制转换数值。这些可调用函数特定于正在使用的 Numeric 的特定类型,以及是否存在任何 SQLAlchemy 类型对象。观察到了一些场景,其中 Oracle 可能发送有关正在返回的数值类型的未完成或含糊信息,例如查询中数值类型被埋在多个级别的子查询中。类型处理程序尽其所能做出正确的决定,并在所有驱动程序可以做出最佳决定的情况下,委托给底层的 cx_Oracle DBAPI。

当不存在任何类型对象时,例如执行纯 SQL 字符串时,会存在一个默认的“outputtypehandler”,它通常会返回将精度和比例指定为 Python Decimal 对象的数值。为了出于性能原因禁用这种强制转换为小数,请将标志 coerce_to_decimal=False 传递给 create_engine()

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

coerce_to_decimal 标志仅影响与 Numeric SQLAlchemy 类型(或此类类型的子类)无关的纯字符串 SQL 语句的结果。

在版本 1.2 中更改: cx_Oracle 的数值处理系统已重新设计,以利用更新的 cx_Oracle 功能以及更好的 outputtypehandler 集成。

python-oracledb

通过 python-oracledb 驱动程序支持 Oracle 数据库。

DBAPI

python-oracledb 的文档和下载信息(如果适用)可在以下网站获得: https://oracle.github.io/python-oracledb/

连接

连接字符串

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

描述

python-oracledb 由 Oracle 发布,以取代 cx_Oracle 驱动程序。它与 cx_Oracle 完全兼容,并具有两种模式:“瘦”客户端模式,它不需要任何依赖项,以及“厚”客户端模式,它以与 cx_Oracle 相同的方式使用 Oracle Client Interface。

版本 1.3.22 中的更改: 如果由于 Oracle 安装中 v$transaction 的权限问题导致无法读取默认隔离级别,则默认隔离级别将硬编码为“READ COMMITTED”,这是 1.3.21 之前的行为。

cx_Oracle - cx_Oracle 的所有注释都适用于 oracledb 驱动程序,除了 oracledb 支持两阶段事务。

SQLAlchemy 的 oracledb 方言在同一个方言名称下提供同步和异步实现。正确的版本将根据引擎的创建方式进行选择

  • 使用 oracle+oracledb://... 调用 create_engine() 将自动选择同步版本,例如

    from sqlalchemy import create_engine
    sync_engine = create_engine("oracle+oracledb://scott:tiger@localhost/?service_name=XEPDB1")
  • 使用 oracle+oracledb://... 调用 create_async_engine() 将自动选择异步版本,例如

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

方言的 asyncio 版本也可以使用 oracledb_async 后缀显式指定,例如

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

在版本 2.0.25 中新增: 添加了对 oracledb 的异步版本的支持。

厚模式支持

默认情况下,python-oracledb 以瘦模式启动,它不需要在系统中安装 oracle 客户端库。 python-oracledb 驱动程序还支持“厚”模式,其行为类似于 cx_oracle,并要求安装 Oracle Client Interface (OCI)。

要启用此模式,用户可以手动调用 oracledb.init_oracle_client,或者通过将参数 thick_mode=True 传递给 create_engine()。要将自定义参数传递给 init_oracle_client,例如 lib_dir 路径,可以将字典传递给此参数,例如

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

版本 1.3.22 中的更改: 如果由于 Oracle 安装中 v$transaction 的权限问题导致无法读取默认隔离级别,则默认隔离级别将硬编码为“READ COMMITTED”,这是 1.3.21 之前的行为。

https://python-oracledb.readthedocs.io/en/latest/api_manual/module.html#oracledb.init_oracle_client

支持两阶段事务

oracledb 完全支持两阶段事务。从 oracledb 2.3 开始,瘦模式也支持两阶段事务。两阶段事务的 API 通过 Connection.begin_twophase()Session.twophase 在 Core 级提供,用于透明的 ORM 使用。

在版本 2.0.32 中更改: 添加了对两阶段事务的支持

在版本 2.0.0 中新增: 添加了对 oracledb 驱动程序的支持。