Microsoft SQL 服务器


支持 Microsoft SQL Server 数据库。


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


支持的 Microsoft SQL Server 版本


支撑类型


版本


支持的版本

2012+


尽力而为

2005+


DBAPI 支持


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


外部方言


除了上述支持本机 SQLAlchemy 的 DBAPI 层外,还有 是其他兼容的 DBAPI 层的第三方方言 使用 SQL Server。请参阅 上的 “External Dialects” 列表 方言页面。


Auto Increment Behavior / IDENTITY 列


SQL Server 使用 IDENTITY 结构,该结构可以放置在表中的任何单个整数列上。SQLAlchemy 在其默认的 “autoincrement” 中考虑 IDENTITY 整数主键列的行为,如 这意味着默认情况下,Table 中的第一个整数主键列将为 被视为 Identity 列 - 除非它与 Sequence - 并将生成 DDL,如下所示:

from sqlalchemy import Table, MetaData, Column, Integer

m = MetaData()
t = Table(
    "t",
    m,
    Column("id", Integer, primary_key=True),
    Column("x", Integer),
)
m.create_all(engine)


上面的示例将生成 DDL 为:

CREATE TABLE t (
    id INTEGER NOT NULL IDENTITY,
    x INTEGER NULL,
    PRIMARY KEY (id)
)


对于不需要这种默认生成的 IDENTITY 的情况,请在第一个整数主键列上为 Column.autoincrement 标志指定 False

m = MetaData()
t = Table(
    "t",
    m,
    Column("id", Integer, primary_key=True, autoincrement=False),
    Column("x", Integer),
)
m.create_all(engine)


要将 IDENTITY 关键字添加到非主键列,请指定 True,表示所需 Column 对象,并确保 Column.autoincrement 在任何整数主键列上设置为 False

m = MetaData()
t = Table(
    "t",
    m,
    Column("id", Integer, primary_key=True, autoincrement=False),
    Column("x", Integer, autoincrement=True),
)
m.create_all(engine)


在 1.4 版本发生变更: Column 中添加了 Identity 结构,用于指定 IDENTITY 的 start 和 increment 参数。这些值取代了 Sequence 对象的使用,以便指定这些值。


1.4 版后已移除: Columnmssql_identity_startmssql_identity_increment 参数已弃用,我们应该用 Identity 对象替换。指定两种配置 IDENTITY 将导致编译错误。 这些选项也不再作为 dialect_options键入 Inspector.get_columns() 。请改用身份密钥中的信息。


1.3 版后已移除: 使用 Sequence 指定 IDENTITY 特征的功能已弃用,并将在将来的发行版中删除。请使用 Identity 对象参数 Identity.startIdentity.increment 中。


在 1.4 版本发生变更: 删除了使用 Sequence 的功能 object 修改 IDENTITY 特征。Sequence 对象现在仅作真正的 T-SQL SEQUENCE 类型。


注意


表中只能有一个 IDENTITY 列。 使用 autoincrement=True 启用 IDENTITY 关键字,SQLAlchemy 不会防止多个列同时指定该选项。SQL Server 数据库将拒绝 CREATE TABLE 语句。


注意


尝试为标记为 IDENTITY 的列提供值的 INSERT 语句将被 SQL Server 拒绝。为了接受该值,必须启用会话级选项 “SET IDENTITY_INSERT”。SQLAlchemy SQL Server 方言将在使用核心 Insert 时自动执行此作 构建;如果 execution 指定 IDENTITY 列的值,即 “IDENTITY_INSERT” 选项。然而 此方案的性能不高,不应依赖 正常使用。 如果表实际上不需要在其 integer primary key 列,则在创建 通过确保设置 autoincrement=False 来执行表。


控制 “Start” 和 “Increment”


IDENTITY 生成器的 “start” 和 “increment” 值的特定控制是使用 Identity.startIdentity.increment 传递给 Identity 对象的参数:

from sqlalchemy import Table, Integer, Column, Identity

test = Table(
    "test",
    metadata,
    Column(
        "id", Integer, primary_key=True, Identity(start=100, increment=10)
    ),
    Column("name", String(20)),
)


上述 Table 对象的 CREATE TABLE 将为:

CREATE TABLE test (
  id INTEGER NOT NULL IDENTITY(100,10) PRIMARY KEY,
  name VARCHAR(20) NULL,
)


注意


Identity 对象除了 startincrement 之外还支持许多其他参数。SQL Server 不支持这些选项,在生成 CREATE TABLE ddl 时将被忽略。


在 1.3.19 版本发生变更: Identity 对象为 现在用于影响 SQL Server 下的 Column 的 IDENTITY 生成器。以前,使用的是 Sequence 对象。由于 SQL Server 现在支持将真实序列作为单独的构造,因此 SQLAlchemy 版本 1.4 开始,Sequence 将以正常方式运行。


将 IDENTITY 与非整数数字类型一起使用


SQL Server 还允许将 IDENTITYNUMERIC 列一起使用。要在 SQLAlchemy 中顺利实现此模式,列的主要数据类型应保持为 Integer,但是部署到 SQL Server 数据库的基础实现类型可以使用 TypeEngine.with_variant() 中:

from sqlalchemy import Column
from sqlalchemy import Integer
from sqlalchemy import Numeric
from sqlalchemy import String
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()


class TestTable(Base):
    __tablename__ = "test"
    id = Column(
        Integer().with_variant(Numeric(10, 0), "mssql"),
        primary_key=True,
        autoincrement=True,
    )
    name = Column(String)


在上面的示例中,Integer().with_variant() 提供了准确的 intent 的明确用法信息。autoincrement 仅适用于 Integer 的一般限制是在元数据级别建立的,而不是在每个方言级别建立的。


当使用上述模式时,从插入行返回的主键标识符(也是将分配给 ORM 对象(如上面的 TestTable)的值)将是 Decimal() 的实例 而不是 int 。该 可以通过将 False 传递给 Numeric.asdecimal 来更改数值类型以返回浮点数。要将上述 Numeric(10, 0) 的返回类型规范化以返回 Python 整数(在 Python 3 中也支持“长”整数值),请使用 TypeDecorator,如下所示:

from sqlalchemy import TypeDecorator


class NumericAsInteger(TypeDecorator):
    "normalize floating point return values into ints"

    impl = Numeric(10, 0, asdecimal=False)
    cache_ok = True

    def process_result_value(self, value, dialect):
        if value is not None:
            value = int(value)
        return value


class TestTable(Base):
    __tablename__ = "test"
    id = Column(
        Integer().with_variant(NumericAsInteger, "mssql"),
        primary_key=True,
        autoincrement=True,
    )
    name = Column(String)


INSERT 行为


在 INSERT 时处理 IDENTITY 列涉及两种关键技术。最常见的是能够获取给定 IDENTITY 列的“最后插入的值”,SQLAlchemy 在许多情况下隐式执行这一过程,最重要的是在 ORM 中。


获取此值的过程有几种变体:


  • 在绝大多数情况下,RETURNING 与 SQL Server 上的 INSERT 语句结合使用,以获取新生成的主键值:

    INSERT INTO t (x) OUTPUT inserted.id VALUES (?)


    从 SQLAlchemy 2.0 开始,INSERT 语句的“插入多值”行为功能也默认用于优化多行 INSERT 语句;对于 SQL Server,该功能适用于 RETURNING 和非 RETURNING INSERT 语句。


    在 2.0.10 版本发生变更: 由于行排序问题,SQLAlchemy 版本 2.0.9 暂时禁用了 SQL Server 的 INSERT 语句的“插入多个值”行为。从 2.0.10 开始,该功能重新启用,对工作单元对 RETURNING 的要求进行特殊处理。


  • 当 RETURNING 不可用或已通过以下方式禁用时 implicit_returning=False,则使用 scope_identity() 函数或 @@identity 变量;行为因后端而异:


    • 使用 PyODBC 时,短语 ;select scope_identity() 将附加到 INSERT 语句的末尾;将获取第二个结果集以接收该值。给定一个表为:

      t = Table(
          "t",
          metadata,
          Column("id", Integer, primary_key=True),
          Column("x", Integer),
          implicit_returning=False,
      )


      INSERT 将如下所示:

      INSERT INTO t (x) VALUES (?); select scope_identity()

    • 其他方言(如 pymssql)将调用 SELECT scope_identity() AS lastrowid 在 INSERT 语句之后。如果将标志 use_scope_identity=False 传递给 create_engine() 中,语句 SELECT @@identity AS lastrowid


包含 IDENTITY 列的表将禁止 INSERT 语句 显式引用 Identity 列。 SQLAlchemy 方言将 检测使用核心创建的 INSERT 构造 插入() construct(不是纯字符串 SQL)引用标识列,并且 在这种情况下,将在 insert 语句继续之前发出 SET IDENTITY_INSERT ON,并在执行之后发出 SET IDENTITY_INSERT OFF。给定此示例:

m = MetaData()
t = Table(
    "t", m, Column("id", Integer, primary_key=True), Column("x", Integer)
)
m.create_all(engine)

with engine.begin() as conn:
    conn.execute(t.insert(), {"id": 1, "x": 1}, {"id": 2, "x": 2})


上面的列将使用 IDENTITY 创建,但是我们发出的 INSERT 语句指定了显式值。在 echo 输出中,我们可以看到 SQLAlchemy 是如何处理这个问题的:

CREATE TABLE t (
    id INTEGER NOT NULL IDENTITY(1,1),
    x INTEGER NULL,
    PRIMARY KEY (id)
)

COMMIT
SET IDENTITY_INSERT t ON
INSERT INTO t (id, x) VALUES (?, ?)
((1, 1), (2, 2))
SET IDENTITY_INSERT t OFF
COMMIT


这是一个适用于测试和批量插入场景的辅助用例。


SEQUENCE 支持


Sequence 对象创建“真实”序列,即 创建序列

>>> from sqlalchemy import Sequence
>>> from sqlalchemy.schema import CreateSequence
>>> from sqlalchemy.dialects import mssql
>>> print(
...     CreateSequence(Sequence("my_seq", start=1)).compile(
...         dialect=mssql.dialect()
...     )
... )
CREATE SEQUENCE my_seq START WITH 1


对于整数主键生成,SQL Server 的 IDENTITY 构造通常应优先于 sequence。


提示


T-SQL 的默认起始值为 -2**63 而不是 1,因为 在大多数其他 SQL 数据库中。用户应显式设置 Sequence.start 设置为 1(如果这是预期的默认值):

seq = Sequence("my_sequence", start=1)


在 1.4 版本加入: 添加了对 Sequence 的 SQL Server 支持


在 2.0 版更改: SQL Server 方言将不再隐式呈现 CREATE SEQUENCE 的 “START WITH 1”,这是在 1.4 版中首次实现的行为。


VARCHAR / NVARCHAR 上的 MAX


SQL Server 支持在 VARCHARNVARCHAR 数据类型,以指示“最大可能的长度”。dialect 当前将其作为基类型中的 “None” 长度处理,而不是提供这些类型的特定于 dialect 的版本,以便指定的 base 类型(如 VARCHAR(None))可以在多个后端上承担 “unlengthed” 行为,而无需使用特定于 dialect 的类型。


要构建具有最大长度的 SQL Server VARCHAR 或 NVARCHAR,请使用 None:

my_table = Table(
    "my_table",
    metadata,
    Column("my_data", VARCHAR(None)),
    Column("my_n_data", NVARCHAR(None)),
)


排序规则支持


字符排序规则由基本字符串类型支持,由字符串参数 “collation” 指定:

from sqlalchemy import VARCHAR

Column("login", VARCHAR(32, collation="Latin1_General_CI_AS"))


当此类列与 Table 关联时,此列的 CREATE TABLE 语句将生成:

login VARCHAR(32) COLLATE Latin1_General_CI_AS NULL


LIMIT/OFFSET 支持


从 SQL Server 2012 开始,MSSQL 通过“OFFSET n ROWS”和“FETCH NEXT n ROWS”子句添加了对 LIMIT / OFFSET 的支持。如果检测到 SQL Server 2012 或更高版本,SQLAlchemy 会自动支持这些语法。


在 1.4 版本发生变更: 添加了对 SQL Server “OFFSET n ROWS” 和 “FETCH NEXT n ROWS” 语法的支持。


对于仅指定 LIMIT 而不指定 OFFSET 的语句,所有版本的 SQL Server 都支持 TOP 关键字。当不存在 OFFSET 子句时,此语法用于所有 SQL Server 版本。如下语句:

select(some_table).limit(5)


将呈现为:

SELECT TOP 5 col1, col2.. FROM table


对于 SQL Server 2012 之前的 SQL Server 版本,使用 LIMIT 和 OFFSET,或者单独使用 OFFSET 渲染,将使用 ROW_NUMBER() 窗口函数。如下语句:

select(some_table).order_by(some_table.c.col3).limit(5).offset(10)


将呈现为:

SELECT anon_1.col1, anon_1.col2 FROM (SELECT col1, col2,
ROW_NUMBER() OVER (ORDER BY col3) AS
mssql_rn FROM table WHERE t.x = :x_1) AS
anon_1 WHERE mssql_rn > :param_1 AND mssql_rn <= :param_2 + :param_1


请注意,当使用 LIMIT 和/或 OFFSET 时,无论是使用较旧的还是较新的 SQL Server 语法,该语句也必须具有 ORDER BY,否则会引发 CompileError


DDL 注释支持


注释支持,包括对 Table.commentColumn.comment 以及反映这些注释的功能(假设正在使用受支持的 SQL Server 版本)都受支持。如果在首次连接时检测到不受支持的版本(如 Azure Synapse)(基于是否存在 fn_listextendedproperty SQL 函数),则会禁用包括呈现和表注释反射在内的注释支持,因为这两项功能都依赖于 SQL Server 存储过程和函数,而这些存储和函数并非在所有后端类型上都可用。


要强制打开或关闭注释支持,绕过自动检测,请在 create_engine() 中设置参数 supports_comments

e = create_engine("mssql+pyodbc://u:p@dsn", supports_comments=False)


2.0 版本中的新功能: 添加了对 SQL Server 方言的表和列注释的支持,包括 DDL 生成和反射。


事务隔离级别


所有 SQL Server dialect 都支持设置事务隔离级别 两者都通过特定于 dialect 的参数 create_engine.isolation_levelcreate_engine() 接受,以及 Connection.execution_options.isolation_level 参数传递给 Connection.execution_options() 。此功能通过为每个新连接发出命令 SET TRANSACTION ISOLATION LEVEL <level> 来实现。


要使用 create_engine() 设置隔离级别:

engine = create_engine(
    "mssql+pyodbc://scott:tiger@ms_2008", isolation_level="REPEATABLE READ"
)


要使用每个连接的执行选项进行设置,请执行以下作:

connection = engine.connect()
connection = connection.execution_options(isolation_level="READ COMMITTED")


isolation_level 的有效值包括:


  • AUTOCOMMIT - 特定于 pyodbc / pymssql


  • 读取已提交


  • 读取 UNCOMMITTED


  • 可重复读取


  • 序列 化


  • SNAPSHOT - 特定于 SQL Server


隔离级别配置还有更多选项,例如链接到主引擎的“子引擎”对象,每个选项都适用 不同的隔离级别设置。 请参阅讨论 设置事务隔离级别,包括 DBAPI 自动提交作为背景。


连接池的临时 Table / Resource 重置


SQLAlchemy Engine 对象使用的 QueuePool 连接池实现包括 reset on return 行为,该行为将在连接返回到池时调用 DBAPI .rollback() 方法。虽然此回滚将清除前一个事务使用的即时状态,但它并不涵盖更广泛的会话级状态,包括临时表以及其他服务器状态,例如准备好的语句句柄和语句缓存。已知称为 sp_reset_connection 的未记录的 SQL Server 过程是此问题的解决方法,它将重置连接上构建的大部分会话状态,包括临时表。


要将 sp_reset_connection 安装为执行 reset-on-return 的方法,可以使用 PoolEvents.reset() 事件钩子,如下例所示。该 create_engine.pool_reset_on_return 参数设置为 None,以便自定义方案可以完全替换默认行为。自定义钩子实现在任何情况下都会调用 .rollback() ,因为 DBAPI 自己的提交/回滚跟踪与事务状态保持一致通常很重要:

from sqlalchemy import create_engine
from sqlalchemy import event

mssql_engine = create_engine(
    "mssql+pyodbc://scott:tiger^5HHH@mssql2017:1433/test?driver=ODBC+Driver+17+for+SQL+Server",
    # disable default reset-on-return scheme
    pool_reset_on_return=None,
)


@event.listens_for(mssql_engine, "reset")
def _reset_mssql(dbapi_connection, connection_record, reset_state):
    if not reset_state.terminate_only:
        dbapi_connection.execute("{call sys.sp_reset_connection}")

    # so that the DBAPI itself knows that the connection has been
    # reset
    dbapi_connection.rollback()


在 2.0.0b3 版本发生变更: PoolEvents.reset() 事件添加了额外的状态参数,并额外确保为所有 “reset” 事件调用该事件,以便它适合作为自定义 “reset” 处理程序的位置。以前使用 PoolEvents.checkin() 处理程序的方案也仍然可用。


另请参阅


Return 时重置 - 在 Connection Pooling 文档中


可空性¶


MSSQL 支持三个级别的列可为 null 性。默认为 null 性允许 null,并且在 CREATE TABLE 构造中是显式的:

name VARCHAR(20) NULL


如果指定了 nullable=None,则不进行指定。换句话说,使用数据库的已配置默认值。这将呈现:

name VARCHAR(20)


如果 nullableTrueFalse,则列将为 NULLNOT NULL


日期 / 时间处理


支持 DATE 和 TIME。根据大多数 MSSQL 驱动程序的要求,绑定参数将转换为 datetime.datetime() 对象,并根据需要从字符串处理结果。DATE 和 TIME 类型不适用于 MSSQL 2005 及更早版本 - 如果检测到低于 2008 的服务器版本,则这些类型的 DDL 将作为 DATETIME 发出。


大文本/二进制类型弃用


SQL Server 2012/2014 文档NTEXT、TEXTIMAGE 数据类型将从 SQL 中删除 Server 的 Server 版本。 SQLAlchemy 通常将这些类型与 UnicodeTextTextClauseLargeBinary 数据类型。


为了适应此更改,deprecate_large_types 个新标志 已添加到 dialect 中,该 dialect 将根据检测结果自动设置 如果用户未另行设置,则为正在使用的服务器版本。 这 此标志的行为如下:


  • 当此标志为 True 时,UnicodeText TextClauseLargeBinary 数据类型在用于呈现 DDL 时,将分别呈现类型 NVARCHAR(max)、VARCHAR(max)VARBINARY(max)。这是添加此标志后的新行为。


  • 当此标志为 False 时,UnicodeTextTextClauseLargeBinary 数据类型在用于呈现 DDL 时,将分别呈现类型 NTEXTTEXTIMAGE。这是这些类型的长期行为。


  • 在建立数据库连接之前,该标志以值 None 开头。如果使用方言来呈现 DDL 而未设置标志,则其解释与 False 相同。


  • 首次连接时,方言会检测是否正在使用 SQL Server 版本 2012 或更高版本;如果标志仍为 None,则将其设置为 TrueFalse,具体取决于是否检测到 2012 或更高版本。


  • 创建方言时,该标志可以设置为 TrueFalse,通常通过 create_engine() 进行

    eng = create_engine(
        "mssql+pymssql://user:pass@host/db", deprecate_large_types=True
    )

  • 通过使用 UPPERCASE 类型对象,所有 SQLAlchemy 版本都可以完全控制是否呈现“旧”或“新”类型:NVARCHAR、VARCHAR、 VARBINARY、TEXT、NTEXT、 图像 将始终保持固定,并始终准确输出 类型。


Multipart Schema 名称


SQL Server 架构有时需要其“架构”限定符的多个部分,即,包括数据库名称和所有者名称作为单独的标记,例如 mydatabase.dbo.some_table。可以使用 Table.schema 的 Table.schema 参数一次性设置这些多部分名称

Table(
    "some_table",
    metadata,
    Column("q", String(50)),
    schema="mydatabase.dbo",
)


在执行表或组件反射等作时,包含点的架构参数将被拆分为单独的“数据库”和“所有者”组件,以便正确查询 SQL Server 信息架构表,因为这两个值是单独存储的。此外,在渲染 DDL 或 SQL 的架构名称时,对于区分大小写的名称和其他特殊字符,这两个组件将分别被引用。给定如下参数:

Table(
    "some_table",
    metadata,
    Column("q", String(50)),
    schema="MyDataBase.dbo",
)


上述架构将呈现为 [MyDataBase].dbo,并且在反射中,将使用“dbo”作为所有者,使用“MyDataBase”作为数据库名称进行反映。


要控制如何将架构名称分解为 database / owner,请在名称中指定括号(在 SQL Server 中是引号字符)。在下面,“owner” 将被视为 MyDataBase.dbo,“database” 将被视为 None:

Table(
    "some_table",
    metadata,
    Column("q", String(50)),
    schema="[MyDataBase.dbo]",
)


要使用特殊字符或嵌入的点单独指定数据库和所有者名称,请使用两组括号:

Table(
    "some_table",
    metadata,
    Column("q", String(50)),
    schema="[MyDataBase.Period].[MyOwner.Dot]",
)


在 1.2 版本发生变更: SQL Server 方言现在将括号视为标识符分隔符,将架构拆分为单独的数据库和所有者令牌,以允许在任一名称本身中使用点。


遗留 Schema 模式


非常旧版本的 MSSQL 方言引入了这种行为,即在 SELECT 语句中使用架构限定的表时,将自动设置别名;给定一个表:

account_table = Table(
    "account",
    metadata,
    Column("id", Integer, primary_key=True),
    Column("info", String(100)),
    schema="customer_schema",
)


这种传统的呈现模式将假定 SQL 语句的所有部分都不接受 “customer_schema.account”,如下所示:

>>> eng = create_engine("mssql+pymssql://mydsn", legacy_schema_aliasing=True)
>>> print(account_table.select().compile(eng))
SELECT account_1.id, account_1.info FROM customer_schema.account AS account_1


这种行为模式现在默认为关闭,因为它似乎没有任何作用;但是,在遗留应用程序依赖它的情况下,可以使用 legacy_schema_aliasing 参数来获取 create_engine() 中。


1.4 版后已移除: legacy_schema_aliasing 标志现已弃用,并将在未来发行版中删除。


聚集索引支持


MSSQL 方言通过 mssql_clustered选项。此选项可用于 IndexUniqueConstraint 的 UniqueConstraint 中。和 PrimaryKeyConstraint 的 PrimaryKeyConstraint 中。对于索引,此选项可以与 mssql_columnstore 选项结合使用,以创建聚集列存储索引。


要生成聚集索引,请执行以下作:

Index("my_index", table.c.x, mssql_clustered=True)


它将索引呈现为 CREATE CLUSTERED INDEX my_index ON table (x) .


要生成集群主键,请使用:

Table(
    "my_table",
    metadata,
    Column("x", ...),
    Column("y", ...),
    PrimaryKeyConstraint("x", "y", mssql_clustered=True),
)


例如,它将呈现表为:

CREATE TABLE my_table (
  x INTEGER NOT NULL,
  y INTEGER NOT NULL,
  PRIMARY KEY CLUSTERED (x, y)
)


同样,我们可以使用以下方法生成一个聚类的唯一约束:

Table(
    "my_table",
    metadata,
    Column("x", ...),
    Column("y", ...),
    PrimaryKeyConstraint("x"),
    UniqueConstraint("y", mssql_clustered=True),
)


要显式请求非聚集主键(例如,当需要单独的聚集索引时),请使用:

Table(
    "my_table",
    metadata,
    Column("x", ...),
    Column("y", ...),
    PrimaryKeyConstraint("x", "y", mssql_clustered=False),
)


例如,它将呈现表为:

CREATE TABLE my_table (
  x INTEGER NOT NULL,
  y INTEGER NOT NULL,
  PRIMARY KEY NONCLUSTERED (x, y)
)


列存储索引支持


MSSQL 方言通过 mssql_columnstore 选择。 此选项可用于 Index。它与 mssql_clustered 选项结合使用,以创建聚集列存储索引。


要生成列存储索引,请执行以下作:

Index("my_index", table.c.x, mssql_columnstore=True)


它将索引呈现为 CREATE COLUMNSTORE INDEX my_index ON table (x) .


若要生成聚集列存储索引,请不提供任何列:

idx = Index("my_index", mssql_clustered=True, mssql_columnstore=True)
# required to associate the index with the table
table.append_constraint(idx)


上面将索引渲染为 CREATE CLUSTERED COLUMNSTORE INDEX my_index ON table .


2.0.18 新版功能.


MSSQL 特定的索引选项


除了聚类之外,MSSQL 方言还支持 Index 的其他特殊选项。


包含


mssql_include 选项为给定的字符串名称呈现 INCLUDE(colname):

Index("my_index", table.c.x, mssql_include=["y"])


会将索引呈现为 CREATE INDEX my_index ON table (x) INCLUDE (y)


过滤索引


mssql_where 选项为给定的字符串名称呈现 WHERE(condition):

Index("my_index", table.c.x, mssql_where=table.c.x > 10)


会将索引呈现为 CREATE INDEX my_index ON table (x) WHERE x > 10 .


在 1.3.4 版本加入.


索引排序


索引排序可通过函数表达式获得,例如:

Index("my_index", table.c.x.desc())


会将索引呈现为 CREATE INDEX my_index ON table (x DESC)


另请参阅


功能指标


兼容性级别


MSSQL 支持在数据库级别设置兼容性级别的概念。例如,这允许在 SQL2005 数据库服务器上运行时运行与 SQL2000 兼容的数据库。server_version_info 将始终返回数据库服务器版本信息(在本例中为 SQL2005),而不是兼容性级别信息。因此,如果在向后兼容模式下运行,SQLAlchemy 可能会尝试使用数据库服务器无法解析的 T-SQL 语句。


触发器


默认情况下,SQLAlchemy 使用 OUTPUT INSERTED 通过 IDENTITY 列或其他服务器端默认值获取新生成的主键值。MS-SQL 不允许在具有触发器的表上使用 OUTPUT INSERTED。要基于每个表禁用 OUTPUT INSERTED,请为每个 Table 指定 implicit_returning=False 它有触发器:

Table(
    "mytable",
    metadata,
    Column("id", Integer, primary_key=True),
    # ...,
    implicit_returning=False,
)


声明式:

class MyClass(Base):
    # ...
    __table_args__ = {"implicit_returning": False}


行数支持 / ORM 版本控制


SQL Server 驱动程序返回从 UPDATE 或 DELETE 语句更新的行数的能力可能有限。


在撰写本文时,PyODBC 驱动程序在使用 OUTPUT INSERTED 时无法返回行计数。因此,以前版本的 SQLAlchemy 对诸如“ORM Versioning”功能等功能有限制,该功能依赖于准确的行数,以便将版本号与匹配的行匹配。


SQLAlchemy 2.0 现在根据计数在 RETURNING 中返回的行数来手动检索这些特定用例的“行数”;因此,虽然驱动程序仍然存在此限制,但 ORM 版本控制功能不再受其影响。从 SQLAlchemy 2.0.5 开始,为 pyodbc 驱动程序完全重新启用了 ORM 版本控制。


在 2.0.5 版本发生变更: 恢复了对 pyodbc 驱动程序的 ORM 版本控制支持。以前,在 ORM 刷新期间会发出警告,指出不支持版本控制。


启用快照隔离


SQL Server 具有默认的事务隔离模式,该模式会锁定整个表,并且会导致即使是轻度并发应用程序也具有长时间持有的锁和频繁的死锁。对于现代级别的并发支持,建议为整个数据库启用快照隔离。这是通过在 SQL 提示符处执行的以下 ALTER DATABASE 命令来完成的:

ALTER DATABASE MyDatabase SET ALLOW_SNAPSHOT_ISOLATION ON

ALTER DATABASE MyDatabase SET READ_COMMITTED_SNAPSHOT ON


有关 SQL Server 快照隔离的背景信息,请访问 https://msdn.microsoft.com/en-us/library/ms175095.aspx


SQL Server SQL 构造


对象名称

描述


try_cast(表达式,type_)


为支持它的后端生成一个 TRY_CAST 表达式;这是一个 CAST,对于不可强制转换的转换返回 NULL。


函数 sqlalchemy.dialects.mssql.try_cast表达式_ColumnExpressionOrLiteralArgument[Any]type_:_TypeEngineArgument[_T] TryCast[_T]


为支持它的后端生成一个 TRY_CAST 表达式;这是一个 CAST,对于不可强制转换的转换返回 NULL。


在 SQLAlchemy 中,此构造仅受 SQL Server 方言支持,如果在其他包含的后端上使用,将引发 CompileError。但是,第三方后端也可能支持此结构。


提示


由于 try_cast() 源自 SQL Server 方言,因此它既可以从 sqlalchemy 导入。也可以从 sqlalchemy.dialects.mssql


try_cast() 返回 TryCast 的实例,其行为通常类似于 Cast 构造;在 SQL 级别,CASTTRY_CAST 之间的区别 是 TRY_CAST 为不可强制转换的表达式返回 NULL,例如尝试将字符串 “hi” 强制转换为整数值。


例如:

from sqlalchemy import select, try_cast, Numeric

stmt = select(try_cast(product_table.c.unit_price, Numeric(10, 4)))


上述内容将在 Microsoft SQL Server 上呈现为:

SELECT TRY_CAST (product_table.unit_price AS NUMERIC(10, 4))
FROM product_table


2.0.14 版中的新功能: try_cast() 已从 SQL Server 方言推广为其他方言可能支持的通用结构。


SQL Server 数据类型


与所有 SQLAlchemy 方言一样,所有已知对 SQL Server 有效的 UPPERCASE 类型都可以从顶级方言导入,无论它们源自 sqlalchemy.types 还是本地方言:

from sqlalchemy.dialects.mssql import (
    BIGINT,
    BINARY,
    BIT,
    CHAR,
    DATE,
    DATETIME,
    DATETIME2,
    DATETIMEOFFSET,
    DECIMAL,
    DOUBLE_PRECISION,
    FLOAT,
    IMAGE,
    INTEGER,
    JSON,
    MONEY,
    NCHAR,
    NTEXT,
    NUMERIC,
    NVARCHAR,
    REAL,
    SMALLDATETIME,
    SMALLINT,
    SMALLMONEY,
    SQL_VARIANT,
    TEXT,
    TIME,
    TIMESTAMP,
    TINYINT,
    UNIQUEIDENTIFIER,
    VARBINARY,
    VARCHAR,
)


特定于 SQL Server 或具有特定于 SQL Server 的构造参数的类型如下:


对象名称

描述

BIT


MSSQL BIT 类型。

DATETIME2

DATETIMEOFFSET

DOUBLE_PRECISION


SQL Server DOUBLE PRECISION 数据类型。

IMAGE

JSON


MSSQL JSON 类型。

MONEY

NTEXT


MSSQL NTEXT 类型,适用于最多 2^30 个字符的可变长度 unicode 文本。

REAL


SQL Server REAL 数据类型。

ROWVERSION


实现 SQL Server ROWVERSION 类型。

SMALLDATETIME

SMALLMONEY

SQL_VARIANT

TIME

TIMESTAMP


实现 SQL Server TIMESTAMP 类型。

TINYINT

UNIQUEIDENTIFIER

XML


MSSQL XML 类型。


sqlalchemy.dialects.mssql。位元


MSSQL BIT 类型。


pyodbc 和 pymssql 都将 BIT 列中的值作为 Python <class 'bool'> 返回,因此只是子类 Boolean。


方法 sqlalchemy.dialects.mssql.BIT. __init__create_constraint: bool = False, name:strNone=None, _create_events: bool = True, _adapted_from:SchemaTypeNone=None


继承自 sqlalchemy.types.Boolean.__init__ Boolean 的方法


构造一个布尔值。


参数
  • create_constraint


    默认为 False。如果布尔值生成为 int/smallint,则还要在表上创建一个 CHECK 约束,以确保值为 1 或 0。


    注意


    强烈建议将 CHECK 约束 具有显式名称,以便支持 Schema-Management 关注。 这可以通过设置 Boolean.name 参数中,或者通过设置 适当的命名约定;看 为背景配置 Constraint Naming Conventions


    在 1.4 版本发生变更: - 此标志现在默认为 False,这意味着不会为非本机枚举类型生成 CHECK 约束。


  • name– 如果生成了 CHECK 约束,请指定约束的名称。


sqlalchemy.dialects.mssql。


SQL CHAR 类型。


类签名


sqlalchemy.dialects.mssql.CHARsqlalchemy.types.String


method sqlalchemy.dialects.mssql.CHAR. __init__length:intNone=None, collation:strNone=None


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


创建字符串保持类型。


参数

  • length – 可选,用于 DDL 和 CAST 表达式的列的长度。如果没有 CREATE ,则可以安全地省略 桌子将发布。 某些数据库可能需要 length 在 DDL 中使用,如果 VARCHAR 不包括长度。 值是否为 解释为 bytes 或 characters 是特定于数据库的。


  • 排序规则


    可选,用于 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.mssql。DATETIME2


类签名


sqlalchemy.dialects.mssql.DATETIME2 sqlalchemy.dialects.mssql.base._DateTimeBasesqlalchemy.types.DateTime


sqlalchemy.dialects.mssql。DATETIMEOFFSET的偏移量¶


类签名


sqlalchemy.dialects.mssql.DATETIMEOFFSET sqlalchemy.dialects.mssql.base._DateTimeBasesqlalchemy.types.DateTime


sqlalchemy.dialects.mssql。DOUBLE_PRECISION


SQL Server DOUBLE PRECISION 数据类型。


2.0.11 版本的新Function。


sqlalchemy.dialects.mssql。图像

方法 sqlalchemy.dialects.mssql.IMAGE. __init__length:intNone=None


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


构造 LargeBinary 类型。


参数


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


sqlalchemy.dialects.mssql。JSON格式¶


MSSQL JSON 类型。


从 SQL Server 2016 开始,MSSQL 支持 JSON 格式的数据。


DDL 级别的 JSON 数据类型将数据类型表示为 NVARCHAR(max),但提供 JSON 级别的比较函数以及 Python 强制行为。


每当 base JSON 数据类型用于 SQL Server 后端。


另请参阅


JSON - 通用跨平台 JSON 数据类型的主要文档。


JSON 类型支持 JSON 值的持久化以及 JSON 提供的核心索引作 datatype 来渲染 JSON_VALUE 或在数据库级别JSON_QUERY函数。


SQL Server JSON 类型必须使用 JSON_QUERYJSON_VALUE 函数。这两个函数有一个主要限制,因为它们根据要返回的对象类型是互斥的。JSON_QUERY 函数返回 JSON 字典或列表, 但不能使用单个字符串、数字或布尔元素;这 JSON_VALUE函数返回单个字符串、数字或布尔元素。这两个函数都返回 NULL 或 raise 如果它们未用于正确的预期值,则出错


为了处理这个尴尬的要求,索引访问规则如下:


  1. 当从 JSON 中提取 sub 元素时,如果 JSON 本身就是 JSON 字典或列表,则应使用 Comparator.as_json() 访问器:

    stmt = select(data_table.c.data["some key"].as_json()).where(
        data_table.c.data["some key"].as_json() == {"sub": "structure"}
    )

  2. 从纯布尔值的 JSON 中提取 sub 元素时, string、integer 或 float 中,使用适当的方法 Comparator.as_boolean()Comparator.as_string()Comparator.as_integer()Comparator.as_float() 中:

    stmt = select(data_table.c.data["some key"].as_string()).where(
        data_table.c.data["some key"].as_string() == "some string"
    )


在 1.4 版本加入.


方法 sqlalchemy.dialects.mssql.JSON. __init__none_as_null: bool = False


继承自 sqlalchemy.types.JSON.__init__ JSON 的方法


构造 JSON 类型。


参数


none_as_null=假


如果为 True,则将值 None 保留为 SQL NULL 值,而不是 null 的 JSON 编码。请注意,当此标志为 False 时,null() 构造仍可用于保留 NULL 值,该值可以直接作为参数值传递,该参数值由 JSON 类型专门解释为 SQL NULL:

from sqlalchemy import null

conn.execute(table.insert(), {"data": null()})


注意


JSON.none_as_null 不适用于传递给 Column.defaultColumn.server_default;值为 None 为这些参数传递的表示 “No default present”。


此外,在 SQL 比较表达式中使用时,Python 值 None 继续引用 SQL null,而不是 JSON NULL。JSON.none_as_null 标志显式引用 INSERT 或 UPDATE 语句中值的持久性JSON.零 value 应用于希望比较的 SQL 表达式 JSON null 的 JSON null。


sqlalchemy.dialects.mssql。货币

sqlalchemy.dialects.mssql。非查尔


SQL NCHAR 类型。


类签名


sqlalchemy.dialects.mssql.NCHARsqlalchemy.types.Unicode


method sqlalchemy.dialects.mssql.NCHAR. __init__length:intNone=None, collation:strNone=None


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


创建字符串保持类型。


参数

  • length – 可选,用于 DDL 和 CAST 表达式的列的长度。如果没有 CREATE ,则可以安全地省略 桌子将发布。 某些数据库可能需要 length 在 DDL 中使用,如果 VARCHAR 不包括长度。 值是否为 解释为 bytes 或 characters 是特定于数据库的。


  • 排序规则


    可选,用于 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.mssql。NTEXT的¶


MSSQL NTEXT 类型,适用于最多 2^30 个字符的可变长度 unicode 文本。


方法 sqlalchemy.dialects.mssql.NTEXT. __init__length:intNone=None, collation:strNone=None


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


创建字符串保持类型。


参数

  • length – 可选,用于 DDL 和 CAST 表达式的列的长度。如果没有 CREATE ,则可以安全地省略 桌子将发布。 某些数据库可能需要 length 在 DDL 中使用,如果 VARCHAR 不包括长度。 值是否为 解释为 bytes 或 characters 是特定于数据库的。


  • 排序规则


    可选,用于 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.mssql。NVARCHAR


SQL NVARCHAR 类型。


类签名


sqlalchemy.dialects.mssql.NVARCHARsqlalchemy.types.Unicode


method sqlalchemy.dialects.mssql.NVARCHAR. __init__length:intNone=None, collation:strNone=None


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


创建字符串保持类型。


参数

  • length – 可选,用于 DDL 和 CAST 表达式的列的长度。如果没有 CREATE ,则可以安全地省略 桌子将发布。 某些数据库可能需要 length 在 DDL 中使用,如果 VARCHAR 不包括长度。 值是否为 解释为 bytes 或 characters 是特定于数据库的。


  • 排序规则


    可选,用于 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.mssql。真实


SQL Server REAL 数据类型。


sqlalchemy.dialects.mssql。ROWVERSION


实现 SQL Server ROWVERSION 类型。


ROWVERSION 数据类型是 TIMESTAMP 数据类型的 SQL Server 同义词,但当前的 SQL Server 文档建议将 ROWVERSION 用于未来的新数据类型。


ROWVERSION 数据类型反映(例如,内省)来自 数据库作为自身;返回的数据类型将为 TIMESTAMP 的 TIMESTAMP 中。


这是一种只读数据类型,不支持 INSERT 值。


在 1.2 版本加入.


另请参阅


时间戳


方法 sqlalchemy.dialects.mssql.ROWVERSION. __init__convert_int=False


继承自 sqlalchemy.dialects.mssql.base.TIMESTAMP.__init__ TIMESTAMP 的方法


构造 TIMESTAMP 或 ROWVERSION 类型。


参数


convert_int – 如果为 True,则二进制整数值将在读取时转换为整数。


在 1.2 版本加入.


sqlalchemy.dialects.mssql。SMALLDATETIME


类签名


sqlalchemy.dialects.mssql.SMALLDATETIME sqlalchemy.dialects.mssql.base._DateTimeBasesqlalchemy.types.DateTime


方法 sqlalchemy.dialects.mssql.SMALLDATETIME. __init__timezone bool = False


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


构造新的 DateTime


参数


timezone – 布尔值。 指示 datetime 类型应 启用 Timezone Support(如果 仅限基准日期/时间持有类型。建议在使用此标志时直接使用 TIMESTAMP 数据类型,因为某些数据库包含与支持时区的 TIMESTAMP 数据类型不同的单独通用日期/时间保持类型,例如 Oracle Database。


sqlalchemy.dialects.mssql。小钱

sqlalchemy.dialects.mssql。SQL_VARIANT

sqlalchemy.dialects.mssql。发短信


SQL TEXT 类型。


类签名


sqlalchemy.dialects.mssql.TEXTsqlalchemy.types.Text


method sqlalchemy.dialects.mssql.TEXT. __init__length:intNone=None, collation:strNone=None


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


创建字符串保持类型。


参数

  • length – 可选,用于 DDL 和 CAST 表达式的列的长度。如果没有 CREATE ,则可以安全地省略 桌子将发布。 某些数据库可能需要 length 在 DDL 中使用,如果 VARCHAR 不包括长度。 值是否为 解释为 bytes 或 characters 是特定于数据库的。


  • 排序规则


    可选,用于 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.mssql。时间

sqlalchemy.dialects.mssql。时间戳


实现 SQL Server TIMESTAMP 类型。


请注意,这与 SQL Server 不支持的 SQL 标准 TIMESTAMP 类型完全不同。它是一种只读数据类型,不支持 INSERT 值。


在 1.2 版本加入.


另请参阅

ROWVERSION


类签名


sqlalchemy.dialects.mssql.TIMESTAMP sqlalchemy.types._Binary


方法 sqlalchemy.dialects.mssql.TIMESTAMP. __init__convert_int=False


构造 TIMESTAMP 或 ROWVERSION 类型。


参数


convert_int – 如果为 True,则二进制整数值将在读取时转换为整数。


在 1.2 版本加入.


sqlalchemy.dialects.mssql。TINYINT的¶

sqlalchemy.dialects.mssql。UNIQUEIDENTIFIER

方法 sqlalchemy.dialects.mssql.UNIQUEIDENTIFIER. __init__as_uuid: bool = True


构造 UNIQUEIDENTIFIER 类型。


参数


as_uuid=真


如果为 True,则值将被解释为 Python uuid 对象,通过 DBAPI 与字符串相互转换。


sqlalchemy.dialects.mssql。VARBINARY


MSSQL VARBINARY 类型。


此类型向核心 VARBINARY 添加了其他功能 类型,包括 “deprecate_large_types” 模式,其中 将呈现 VARBINARY(max) 或 IMAGE,以及 SQL Server FILESTREAM 选项。


类签名


sqlalchemy.dialects.mssql.VARBINARYsqlalchemy.types.VARBINARYsqlalchemy.types.LargeBinary


方法 sqlalchemy.dialects.mssql.VARBINARY. __init__length=Nonefilestream=False


构造 VARBINARY 类型。


参数

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

  • filestream=False


    如果为 True,则在表定义中呈现 FILESTREAM 关键字。在这种情况下,length 必须为 None'max'


    在 1.4.31 版本加入.


sqlalchemy.dialects.mssql。瓦查尔


SQL VARCHAR 类型。


类签名


sqlalchemy.dialects.mssql.VARCHARsqlalchemy.types.String


method sqlalchemy.dialects.mssql.VARCHAR. __init__length:intNone=None, collation:strNone=None


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


创建字符串保持类型。


参数

  • length – 可选,用于 DDL 和 CAST 表达式的列的长度。如果没有 CREATE ,则可以安全地省略 桌子将发布。 某些数据库可能需要 length 在 DDL 中使用,如果 VARCHAR 不包括长度。 值是否为 解释为 bytes 或 characters 是特定于数据库的。


  • 排序规则


    可选,用于 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.mssql。XML格式¶


MSSQL XML 类型。


这是一个用于反射目的的占位符类型,不包括任何 Python 端数据类型支持。它目前也不支持其他参数,例如 “CONTENT”、“DOCUMENT”、“xml_schema_collection”。


方法 sqlalchemy.dialects.mssql.XML. __init__length:intNone=None, collation:strNone=None


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


创建字符串保持类型。


参数

  • length – 可选,用于 DDL 和 CAST 表达式的列的长度。如果没有 CREATE ,则可以安全地省略 桌子将发布。 某些数据库可能需要 length 在 DDL 中使用,如果 VARCHAR 不包括长度。 值是否为 解释为 bytes 或 characters 是特定于数据库的。


  • 排序规则


    可选,用于 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。这些数据类型将确保在数据库上使用正确的类型。


PyODBC的¶


通过 PyODBC 驱动程序支持 Microsoft SQL Server 数据库。


数据库接口


PyODBC 的文档和下载信息(如果适用)可从以下位置获得: https://pypi.org/project/pyodbc/


连接


连接字符串:

mssql+pyodbc://<username>:<password>@<dsnname>


连接到 PyODBC


此处的 URL 将转换为 PyODBC 连接字符串,如 ConnectionStrings 中所述。


DSN 连接


ODBC 中的 DSN 连接意味着在客户端计算机上配置了预先存在的 ODBC 数据源。然后,应用程序指定此数据源的名称,其中包含正在使用的特定 ODBC 驱动程序以及数据库的网络地址等详细信息。假设在客户端上配置了数据源,则基于 DSN 的基本连接如下所示:

engine = create_engine("mssql+pyodbc://scott:tiger@some_dsn")


上面,将以下连接字符串传递给 PyODBC:

DSN=some_dsn;UID=scott;PWD=tiger


如果省略用户名和密码,DSN 表单还会将 Trusted_Connection=yes 指令添加到 ODBC 字符串中。


主机名连接


pyodbc 也支持基于主机名的连接。这些名称通常比 DSN 更易于使用,并且具有额外的优势,即可以在 URL 中本地指定要连接的特定数据库名称,而不是将其作为数据源配置的一部分进行固定。


使用主机名连接时,还必须在 URL 的查询参数中指定驱动程序名称。由于这些名称中通常包含空格,因此名称必须经过 URL 编码,这意味着对空格使用加号:

engine = create_engine(
    "mssql+pyodbc://scott:tiger@myhost:port/databasename?driver=ODBC+Driver+17+for+SQL+Server"
)


driver 关键字对于 pyodbc 方言很重要,必须以小写形式指定。


在查询字符串中传递的任何其他名称都会在 pyodbc 连接字符串中传递,例如 authenticationTrustServerCertificate 等。多个关键字参数必须用 & 符号 (&) 分隔;当 PyODBC Connect 字符串在内部生成时,这些将被转换为分号:

e = create_engine(
    "mssql+pyodbc://scott:tiger@mssql2017:1433/test?"
    "driver=ODBC+Driver+18+for+SQL+Server&TrustServerCertificate=yes"
    "&authentication=ActiveDirectoryIntegrated"
)


等效 URL 可以使用 URL 构建:

from sqlalchemy.engine import URL

connection_url = URL.create(
    "mssql+pyodbc",
    username="scott",
    password="tiger",
    host="mssql2017",
    port=1433,
    database="test",
    query={
        "driver": "ODBC Driver 18 for SQL Server",
        "TrustServerCertificate": "yes",
        "authentication": "ActiveDirectoryIntegrated",
    },
)


传递精确的 Pyodbc 字符串


PyODBC 连接字符串也可以使用参数 odbc_connectPyODBC 文档中指定的 pyodbc 格式直接发送。URL 对象可以帮助简化此作:

from sqlalchemy.engine import URL

connection_string = "DRIVER={SQL Server Native Client 10.0};SERVER=dagger;DATABASE=test;UID=user;PWD=password"
connection_url = URL.create(
    "mssql+pyodbc", query={"odbc_connect": connection_string}
)

engine = create_engine(connection_url)


使用访问令牌连接到数据库


某些数据库服务器设置为仅接受用于登录的访问令牌。为 例如,SQL Server 允许使用 Azure Active Directory 令牌进行连接 到数据库。这需要使用 azure-identity 库。有关身份验证步骤的更多信息,请参阅 Microsoft 的文档


获取引擎后,需要将凭证发送到 pyodbc.connect 每次请求连接时。一种方法是设置事件 将凭证令牌添加到 Dialect 的 Connect 的引擎上的 listener 叫。这在生成动态身份验证令牌中进行了更一般的讨论。特别是对于 SQL Server,这是作为 ODBC 连接属性传递的,该属性具有 Microsoft 描述的数据结构。


以下代码片段将创建一个使用 Azure 凭据连接到 Azure SQL 数据库的引擎:

import struct
from sqlalchemy import create_engine, event
from sqlalchemy.engine.url import URL
from azure import identity

# Connection option for access tokens, as defined in msodbcsql.h
SQL_COPT_SS_ACCESS_TOKEN = 1256
TOKEN_URL = "https://database.windows.net/"  # The token URL for any Azure SQL database

connection_string = "mssql+pyodbc://@my-server.database.windows.net/myDb?driver=ODBC+Driver+17+for+SQL+Server"

engine = create_engine(connection_string)

azure_credentials = identity.DefaultAzureCredential()


@event.listens_for(engine, "do_connect")
def provide_token(dialect, conn_rec, cargs, cparams):
    # remove the "Trusted_Connection" parameter that SQLAlchemy adds
    cargs[0] = cargs[0].replace(";Trusted_Connection=Yes", "")

    # create token credential
    raw_token = azure_credentials.get_token(TOKEN_URL).token.encode(
        "utf-16-le"
    )
    token_struct = struct.pack(
        f"<I{len(raw_token)}s", len(raw_token), raw_token
    )

    # apply it to keyword arguments
    cparams["attrs_before"] = {SQL_COPT_SS_ACCESS_TOKEN: token_struct}


提示


Trusted_Connection 令牌当前由 SQLAlchemy 添加 pyodbc dialect (如果不存在用户名或密码)。 这需要 根据 Microsoft 的 Azure 访问令牌的文档, 声明使用访问令牌时的连接字符串不能包含 UIDPWD身份验证Trusted_Connection 参数。


为 Azure SQL 数据仓库 (DW) 连接启用自动提交


Azure SQL 数据仓库不支持事务,这可能会导致 SQLAlchemy 的“自动开始”(和隐式提交/回滚)行为出现问题。我们可以通过在 pyodbc 和 engine 级别启用 autocommit 来避免这些问题:

connection_url = sa.engine.URL.create(
    "mssql+pyodbc",
    username="scott",
    password="tiger",
    host="dw.azure.example.com",
    database="mydb",
    query={
        "driver": "ODBC Driver 17 for SQL Server",
        "autocommit": "True",
    },
)

engine = create_engine(connection_url).execution_options(
    isolation_level="AUTOCOMMIT"
)


避免以 TEXT/NTEXT 格式发送大型字符串参数


默认情况下,由于历史原因,Microsoft 的 SQL Server ODBC 驱动程序将长字符串参数(大于 4000 个 SBCS 字符或 2000 个 Unicode 字符)作为 TEXT/NTEXT 值发送。TEXT 和 NTEXT 已弃用多年,并开始导致与较新版本的 SQL_Server/Azure 的兼容性问题。例如,请参阅此 问题


从适用于 SQL Server 的 ODBC 驱动程序 18 开始,我们可以覆盖旧版 行为,并使用 LongAsMax=Yes 连接字符串参数:

connection_url = sa.engine.URL.create(
    "mssql+pyodbc",
    username="scott",
    password="tiger",
    host="mssqlserver.example.com",
    database="mydb",
    query={
        "driver": "ODBC Driver 18 for SQL Server",
        "LongAsMax": "Yes",
    },
)


Pyodbc 池化 / 连接关闭行为


PyODBC 默认使用内部,这意味着连接的寿命将比它们在 SQLAlchemy 本身中的时间更长。由于 SQLAlchemy 有自己的池化行为,因此通常最好禁用此行为。在建立任何连接之前,只能在 PyODBC 模块级别全局禁用此行为:

import pyodbc

pyodbc.pooling = False

# don't use the engine before pooling is set to False
engine = create_engine("mssql+pyodbc://user:pass@dsn")


如果此变量保留为默认值 True则应用程序 将继续保持活动的数据库连接,即使 SQLAlchemy 引擎本身完全放弃连接或引擎被释放也是如此。


另请参阅


pooling - 在 PyODBC 文档中。


驱动程序 / Unicode 支持


PyODBC 最适合与 Microsoft ODBC 驱动程序配合使用,尤其是在 Python 2 和 Python 3 上的 Unicode 支持方面。


在 Linux 或 OSX 上将 FreeTDS ODBC 驱动程序与 PyODBC 一起使用不是 推荐;历史上存在许多与 Unicode 相关的问题 在此领域,包括在 Microsoft 提供适用于 Linux 的 ODBC 驱动程序之前 和 OSX 的 10 个版本。 现在 Microsoft 为所有平台提供了驱动程序,以便 PyODBC 支持这些是推荐的。 FreeTDS 仍然与 非 ODBC 驱动程序,例如 pymssql,它运行良好。


行数支持


SQLAlchemy ORM 的“版本化行”功能以前的限制 Pyodbc 已在 SQLAlchemy 2.0.5 中得到解决。请参阅注释 行计数支持/ORM 版本控制


Fast Executemany 模式


PyODBC 驱动程序包括对“快速 executemany”执行模式的支持,该模式在使用 Microsoft ODBC 驱动程序时大大减少了 DBAPI executemany() 调用的往返次数,适用于适合内存的有限大小批处理。通过在 DBAPI 上设置属性 .fast_executemany 来启用该功能 cursor 的调用。 The SQLAlchemy PyODBC SQL 服务器方言通过传递 fast_executemany参数设置为 create_engine()当仅使用 Microsoft ODBC 驱动程序时:

engine = create_engine(
    "mssql+pyodbc://scott:tiger@mssql2017:1433/test?driver=ODBC+Driver+17+for+SQL+Server",
    fast_executemany=True,
)


在 2.0.9 版更改: - fast_executemany 参数现在具有此 PyODBC 功能的预期效果,该效果对使用多个参数集(不包括 RETURNING)执行的所有 INSERT 语句生效。以前,SQLAlchemy 2.0 的 insertmanyvalues 功能将导致在大多数情况下不使用 fast_executemany 即使指定了


在 1.3 版本加入.


另请参阅


快速执行许多 - 在 GitHub 上


setinputsizes 支持


从版本 2.0 开始,pyodbc cursor.setinputsizes() 方法用于所有语句执行,除了 cursor.executemany() 调用,当 fast_executemany=True(假设 insertmanyvalues 保持启用状态,则在任何情况下都不会对 INSERT 语句执行 “fastexecutemany”)。


可以通过传递 use_setinputsizes=False 设置为 create_engine()。


use_setinputsizes 保留为默认值 True,可以使用 DialectEvents.do_setinputsizes() 钩。有关使用示例,请参阅该方法。


在 2.0 版更改: mssql+pyodbc 方言现在默认使用 所有语句执行都为 use_setinputsizes=True,但 cursor .executemany() 调用除外,当 fast_executemany=True 时。可以通过将 use_setinputsizes=False 传递给 create_engine() 中。

pymssql


通过 pymssql 驱动程序支持 Microsoft SQL Server 数据库。


连接


连接字符串:

mssql+pymssql://<username>:<password>@<freetds_name>/?charset=utf8


pymssql 是一个 Python 模块,它提供了一个 Python DBAPI 接口 FreeTDS


在 2.0.5 版本发生变更: pymssql 已恢复到 SQLAlchemy 的持续集成测试

aioodbc


通过 aioodbc 驱动程序支持 Microsoft SQL Server 数据库。


数据库接口


aioodbc 的文档和下载信息(如果适用)可在以下网址获得: https://pypi.org/project/aioodbc/


连接


连接字符串:

mssql+aioodbc://<username>:<password>@<dsnname>


使用 aioodbc 驱动程序以 asyncio 样式支持 SQL Server 数据库,该驱动程序本身是 pyodbc 的线程包装器。


2.0.23 版本中的新功能: 添加了 mssql+aioodbc 方言,它构建在 pyodbc 和通用 aio* 方言架构之上。


使用特殊的 asyncio 中介层,aioodbc dialect 可用作 SQLAlchemy asyncio 的后端 扩展包。


此驱动程序的大多数行为和注意事项与 SQL Server 上使用的 pyodbc 方言的行为和注意事项相同;有关一般背景,请参阅 PyODBC


这种方言通常只能与 create_async_engine() 引擎创建函数;连接样式等同于 pyodbc 部分中记录的样式:

from sqlalchemy.ext.asyncio import create_async_engine

engine = create_async_engine(
    "mssql+aioodbc://scott:tiger@mssql2017:1433/test?"
    "driver=ODBC+Driver+18+for+SQL+Server&TrustServerCertificate=yes"
)