Microsoft SQL 服务器¶
支持 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 版后已移除: Column 的 mssql_identity_start 和 mssql_identity_increment 参数已弃用,我们应该用 Identity 对象替换。指定两种配置
IDENTITY 将导致编译错误。
这些选项也不再作为
dialect_options键入 Inspector.get_columns() 。请改用身份密钥中的信息。
1.3 版后已移除: 使用 Sequence 指定 IDENTITY 特征的功能已弃用,并将在将来的发行版中删除。请使用 Identity 对象参数
Identity.start 和
Identity.increment 中。
注意
表中只能有一个 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.start 和 Identity.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 对象除了 start 和 increment 之外还支持许多其他参数。SQL Server 不支持这些选项,在生成 CREATE TABLE ddl 时将被忽略。
将 IDENTITY 与非整数数字类型一起使用¶
SQL Server 还允许将 IDENTITY 与 NUMERIC 列一起使用。要在 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 支持在
VARCHAR 和 NVARCHAR 数据类型,以指示“最大可能的长度”。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.comment 和 Column.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_level
被 create_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)
如果 nullable 为 True 或 False,则列将为
NULL 或 NOT NULL。
日期 / 时间处理¶
支持 DATE 和 TIME。根据大多数 MSSQL 驱动程序的要求,绑定参数将转换为 datetime.datetime() 对象,并根据需要从字符串处理结果。DATE 和 TIME 类型不适用于 MSSQL 2005 及更早版本 - 如果检测到低于 2008 的服务器版本,则这些类型的 DDL 将作为 DATETIME 发出。
大文本/二进制类型弃用¶
每
SQL Server 2012/2014 文档,NTEXT、TEXT 和 IMAGE 数据类型将从 SQL 中删除
Server 的 Server 版本。 SQLAlchemy 通常将这些类型与
UnicodeText、TextClause 和
LargeBinary 数据类型。
为了适应此更改,deprecate_large_types 个新标志
已添加到 dialect 中,该 dialect 将根据检测结果自动设置
如果用户未另行设置,则为正在使用的服务器版本。 这
此标志的行为如下:
当此标志为True时,UnicodeTextTextClause和LargeBinary数据类型在用于呈现 DDL 时,将分别呈现类型NVARCHAR(max)、VARCHAR(max)和VARBINARY(max)。这是添加此标志后的新行为。
当此标志为False时,UnicodeText、TextClause和LargeBinary数据类型在用于呈现 DDL 时,将分别呈现类型NTEXT、TEXT和IMAGE。这是这些类型的长期行为。
在建立数据库连接之前,该标志以值None开头。如果使用方言来呈现 DDL 而未设置标志,则其解释与False相同。
首次连接时,方言会检测是否正在使用 SQL Server 版本 2012 或更高版本;如果标志仍为None,则将其设置为True或False,具体取决于是否检测到 2012 或更高版本。
创建方言时,该标志可以设置为True或False,通常通过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选项。此选项可用于 Index、
UniqueConstraint 的 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 构造¶
对象名称 |
描述 |
|---|---|
|
|
-
函数 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 级别,CAST和TRY_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 的构造参数的类型如下:
对象名称 |
描述 |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-
类 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.CHAR(sqlalchemy.types.String)-
methodsqlalchemy.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
注意
在大多数情况下,Unicode或UnicodeText数据类型应用于预期存储非 ASCII 数据的Column。这些数据类型将确保在数据库上使用正确的类型。
-
-
类 sqlalchemy.dialects.mssql。DATETIME2¶
类签名
类sqlalchemy.dialects.mssql.DATETIME2(sqlalchemy.dialects.mssql.base._DateTimeBase,sqlalchemy.types.DateTime)
-
类 sqlalchemy.dialects.mssql。DATETIMEOFFSET的偏移量¶
类签名
类sqlalchemy.dialects.mssql.DATETIMEOFFSET(sqlalchemy.dialects.mssql.base._DateTimeBase,sqlalchemy.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 强制行为。每当 baseJSON数据类型用于 SQL Server 后端。
另请参阅JSON- 通用跨平台 JSON 数据类型的主要文档。JSON类型支持 JSON 值的持久化以及JSON提供的核心索引作 datatype 来渲染JSON_VALUE或在数据库级别JSON_QUERY函数。
SQL ServerJSON类型必须使用JSON_QUERY和JSON_VALUE函数。这两个函数有一个主要限制,因为它们根据要返回的对象类型是互斥的。JSON_QUERY函数仅返回 JSON 字典或列表, 但不能使用单个字符串、数字或布尔元素;这JSON_VALUE函数仅返回单个字符串、数字或布尔元素。这两个函数都返回 NULL 或 raise 如果它们未用于正确的预期值,则出错。
为了处理这个尴尬的要求,索引访问规则如下:
当从 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"} )
从纯布尔值的 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.default和Column.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.NCHAR(sqlalchemy.types.Unicode)-
methodsqlalchemy.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
注意
在大多数情况下,Unicode或UnicodeText数据类型应用于预期存储非 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
注意
在大多数情况下,Unicode或UnicodeText数据类型应用于预期存储非 ASCII 数据的Column。这些数据类型将确保在数据库上使用正确的类型。
-
-
类 sqlalchemy.dialects.mssql。NVARCHAR
SQL NVARCHAR 类型。
类签名
类sqlalchemy.dialects.mssql.NVARCHAR(sqlalchemy.types.Unicode)-
methodsqlalchemy.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
注意
在大多数情况下,Unicode或UnicodeText数据类型应用于预期存储非 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._DateTimeBase,sqlalchemy.types.DateTime)-
方法sqlalchemy.dialects.mssql.SMALLDATETIME.__init__(timezone: bool = False)¶
继承自sqlalchemy.types.DateTime.__init__DateTime的方法
构造新的DateTime。
-
-
类 sqlalchemy.dialects.mssql。小钱¶
-
类 sqlalchemy.dialects.mssql。SQL_VARIANT¶
-
类 sqlalchemy.dialects.mssql。发短信
SQL TEXT 类型。
类签名
类sqlalchemy.dialects.mssql.TEXT(sqlalchemy.types.Text)-
methodsqlalchemy.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
注意
在大多数情况下,Unicode或UnicodeText数据类型应用于预期存储非 ASCII 数据的Column。这些数据类型将确保在数据库上使用正确的类型。
-
-
类 sqlalchemy.dialects.mssql。时间¶
-
类 sqlalchemy.dialects.mssql。时间戳¶
实现 SQL Server TIMESTAMP 类型。
请注意,这与 SQL Server 不支持的 SQL 标准 TIMESTAMP 类型完全不同。它是一种只读数据类型,不支持 INSERT 值。
在 1.2 版本加入.
另请参阅
成员
类签名
类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 ServerFILESTREAM选项。
另请参阅
类签名
类sqlalchemy.dialects.mssql.VARBINARY(sqlalchemy.types.VARBINARY,sqlalchemy.types.LargeBinary)-
方法sqlalchemy.dialects.mssql.VARBINARY.__init__(length=None, filestream=False)
构造 VARBINARY 类型。
-
-
类 sqlalchemy.dialects.mssql。瓦查尔
SQL VARCHAR 类型。
类签名
类sqlalchemy.dialects.mssql.VARCHAR(sqlalchemy.types.String)-
methodsqlalchemy.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
注意
在大多数情况下,Unicode或UnicodeText数据类型应用于预期存储非 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
注意
在大多数情况下,Unicode或UnicodeText数据类型应用于预期存储非 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 连接字符串中传递,例如 authentication、TrustServerCertificate 等。多个关键字参数必须用 & 符号 (&) 分隔;当 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_connect 以 PyODBC 文档中指定的 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 访问令牌的文档,
声明使用访问令牌时的连接字符串不能包含
UID、PWD、身份验证或 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"
)