SqlAlchemy 2.0 中文文档(五十)(1)https://developer.aliyun.com/article/1563127
额外的 WHERE 条件
Insert.on_conflict_do_update() 方法还接受使用 Insert.on_conflict_do_update.where 参数的 WHERE 子句,这将限制接收 UPDATE 的行:
>>> stmt = insert(my_table).values( ... id='some_id', ... data='inserted value', ... author='jlh' ... ) >>> on_update_stmt = stmt.on_conflict_do_update( ... index_elements=['id'], ... set_=dict(data='updated value', author=stmt.excluded.author), ... where=(my_table.c.status == 2) ... ) >>> print(on_update_stmt) INSERT INTO my_table (id, data, author) VALUES (?, ?, ?) ON CONFLICT (id) DO UPDATE SET data = ?, author = excluded.author WHERE my_table.status = ?
使用 DO NOTHING 跳过行
ON CONFLICT 可用于完全跳过插入行,如果与唯一约束发生冲突;下面使用 Insert.on_conflict_do_nothing() 方法进行说明:
>>> stmt = insert(my_table).values(id='some_id', data='inserted value') >>> stmt = stmt.on_conflict_do_nothing(index_elements=['id']) >>> print(stmt) INSERT INTO my_table (id, data) VALUES (?, ?) ON CONFLICT (id) DO NOTHING
如果使用 DO NOTHING 而没有指定任何列或约束,它将跳过任何唯一性冲突导致的 INSERT:
>>> stmt = insert(my_table).values(id='some_id', data='inserted value') >>> stmt = stmt.on_conflict_do_nothing() >>> print(stmt) INSERT INTO my_table (id, data) VALUES (?, ?) ON CONFLICT DO NOTHING ```## 类型反射 SQLite 类型与大多数其他数据库后端的类型不同,因为类型的字符串名称通常不是一对一对应的“类型”。相反,SQLite 将每列的类型行为链接到五种所谓的“类型亲和性”之一,基于类型的字符串匹配模式。 SQLAlchemy 的反射过程,在检查类型时,使用一个简单的查找表将返回的关键字链接到提供的 SQLAlchemy 类型。这个查找表存在于 SQLite 方言中,就像所有其他方言一样。然而,当特定类型名称未在查找映射中找到时,SQLite 方言有一个不同的“回退”程序;它实际上实现了位于 [`www.sqlite.org/datatype3.html`](https://www.sqlite.org/datatype3.html) 第 2.1 节的 SQLite “类型亲和性”方案。 提供的类型映射将直接从以下类型的精确字符串名称匹配中进行关联: 如果类型名称包含字符串`BLOB`,则返回`BIGINT`、`BLOB`、`BOOLEAN`、`BOOLEAN`、`CHAR`、`DATE`、`DATETIME`、`FLOAT`、`DECIMAL`、`FLOAT`、`INTEGER`、`INTEGER`、`NUMERIC`、`REAL`、`SMALLINT`、`TEXT`、`TIME`、`TIMESTAMP`、`VARCHAR`、`NVARCHAR`、`NCHAR` 当类型名称不匹配上述类型之一时,将使用“类型亲和性”查找代替: + 如果类型名称包含字符串`INT`,则返回`INTEGER` + 如果类型名称包含字符串`CHAR`、`CLOB`或`TEXT`,则返回`TEXT` + 如果类型名称包含字符串`BLOB`,则返回`NullType` + 如果类型名称包含字符串`REAL`、`FLOA`或`DOUB`,则返回`REAL` + 否则,将使用`NUMERIC`类型。## 部分索引 可以使用 DDL 系统使用参数`sqlite_where`来指定部分索引,例如使用 WHERE 子句的索引: ```py tbl = Table('testtbl', m, Column('data', Integer)) idx = Index('test_idx1', tbl.c.data, sqlite_where=and_(tbl.c.data > 5, tbl.c.data < 10))
索引将在创建时呈现为:
CREATE INDEX test_idx1 ON testtbl (data) WHERE data > 5 AND data < 10 ```## 点列名 使用明确包含句点的表格或列名**不推荐**。虽然这通常对关系数据库来说是个坏主意,因为句点是一个语法上重要的字符,但直到 SQLite 版本**3.10.0**之前的 SQLite 驱动程序存在一个 bug,需要 SQLAlchemy 在结果集中过滤掉这些句点。 这个 bug 完全不是 SQLAlchemy 的问题,可以这样说明: ```py import sqlite3 assert sqlite3.sqlite_version_info < (3, 10, 0), "bug is fixed in this version" conn = sqlite3.connect(":memory:") cursor = conn.cursor() cursor.execute("create table x (a integer, b integer)") cursor.execute("insert into x (a, b) values (1, 1)") cursor.execute("insert into x (a, b) values (2, 2)") cursor.execute("select x.a, x.b from x") assert [c[0] for c in cursor.description] == ['a', 'b'] cursor.execute(''' select x.a, x.b from x where a=1 union select x.a, x.b from x where a=2 ''') assert [c[0] for c in cursor.description] == ['a', 'b'], \ [c[0] for c in cursor.description]
第二个断言失败:
Traceback (most recent call last): File "test.py", line 19, in <module> [c[0] for c in cursor.description] AssertionError: ['x.a', 'x.b']
在上述情况下,驱动程序错误地报告包括表名在内的列名,这与没有 UNION 时完全不一致。
SQLAlchemy 依赖于列名在匹配原始语句时的可预测性,因此 SQLAlchemy 方言别无选择,只能过滤掉这些内容:
from sqlalchemy import create_engine eng = create_engine("sqlite://") conn = eng.connect() conn.exec_driver_sql("create table x (a integer, b integer)") conn.exec_driver_sql("insert into x (a, b) values (1, 1)") conn.exec_driver_sql("insert into x (a, b) values (2, 2)") result = conn.exec_driver_sql("select x.a, x.b from x") assert result.keys() == ["a", "b"] result = conn.exec_driver_sql(''' select x.a, x.b from x where a=1 union select x.a, x.b from x where a=2 ''') assert result.keys() == ["a", "b"]
请注意,即使 SQLAlchemy 过滤掉了句点,这两个名称仍然可寻址:
>>> row = result.first() >>> row["a"] 1 >>> row["x.a"] 1 >>> row["b"] 1 >>> row["x.b"] 1
因此,SQLAlchemy 应用的解决方法仅影响公共 API 中的CursorResult.keys()和Row.keys(),在应用被迫使用包含句点的列名,并且需要CursorResult.keys()和Row.keys()返回这些带点的名称时,可以提供sqlite_raw_colnames执行选项,或者基于每个Connection的基础上:
result = conn.execution_options(sqlite_raw_colnames=True).exec_driver_sql(''' select x.a, x.b from x where a=1 union select x.a, x.b from x where a=2 ''') assert result.keys() == ["x.a", "x.b"]
或者基于每个Engine的基础上:
engine = create_engine("sqlite://", execution_options={"sqlite_raw_colnames": True})
在使用基于每个Engine的执行选项时,请注意使用 UNION 的 Core 和 ORM 查询可能无法正常工作。
特定于 SQLite 的表选项
一个 CREATE TABLE 的选项直接由 SQLite 方言支持,与Table构造一起使用:
WITHOUT ROWID:
Table("some_table", metadata, ..., sqlite_with_rowid=False)
另请参见
反射内部模式表
返回表列表的反射方法将省略所谓的“SQLite 内部模式对象”名称,这些名称被 SQLite 视为任何以sqlite_为前缀的对象名称。这种对象的一个例子是在使用AUTOINCREMENT列参数时生成的sqlite_sequence表。为了返回这些对象,可以将参数sqlite_include_internal=True传递给诸如MetaData.reflect()或Inspector.get_table_names()等方法。
新增于版本 2.0:添加了 sqlite_include_internal=True 参数。以前,这些表不会被 SQLAlchemy 反射方法所忽略。
注
sqlite_include_internal 参数不是指与 sqlite_master 等模式中存在的“系统”表相关的内容。
另请参见
SQLite 内部模式对象 - 在 SQLite 文档中。
SQLite 数据类型
与所有 SQLAlchemy 方言一样,所有已知与 SQLite 兼容的大写类型都可以从顶级方言导入,无论它们是来自 sqlalchemy.types 还是本地方言:
from sqlalchemy.dialects.sqlite import ( BLOB, BOOLEAN, CHAR, DATE, DATETIME, DECIMAL, FLOAT, INTEGER, NUMERIC, JSON, SMALLINT, TEXT, TIME, TIMESTAMP, VARCHAR, )
| 对象名称 | 描述 |
| 日期 | 使用字符串在 SQLite 中表示 Python 日期对象。 |
| 日期时间 | 使用字符串在 SQLite 中表示 Python 日期时间对象。 |
| JSON | SQLite JSON 类型。 |
| 时间 | 使用字符串在 SQLite 中表示 Python 时间对象。 |
class sqlalchemy.dialects.sqlite.DATETIME
使用字符串在 SQLite 中表示 Python 日期时间对象。
默认的字符串存储格式为:
"%(year)04d-%(month)02d-%(day)02d %(hour)02d:%(minute)02d:%(second)02d.%(microsecond)06d"
例如:
2021-03-15 12:05:57.105542
默认情况下,传入的存储格式将使用 Python 的 datetime.fromisoformat() 函数解析。
从版本 2.0 开始更改:默认日期时间字符串解析使用 datetime.fromisoformat()。
可以使用 storage_format 和 regexp 参数在一定程度上定制存储格式,例如:
import re from sqlalchemy.dialects.sqlite import DATETIME dt = DATETIME(storage_format="%(year)04d/%(month)02d/%(day)02d " "%(hour)02d:%(minute)02d:%(second)02d", regexp=r"(\d+)/(\d+)/(\d+) (\d+)-(\d+)-(\d+)" )
参数:
storage_format– 格式字符串,将应用于具有键年、月、日、小时、分钟、秒和微秒的字典。regexp– 将应用于传入结果行的正则表达式,替换使用datetime.fromisoformat()解析传入字符串的方法。如果正则表达式包含命名组,则将生成的匹配字典作为关键字参数应用于 Python 的 datetime() 构造函数。否则,如果使用了位置组,则通过*map(int, match_obj.groups(0))调用 datetime() 构造函数以使用位置参数。
类签名
类sqlalchemy.dialects.sqlite.DATETIME(sqlalchemy.dialects.sqlite.base._DateTimeMixin,sqlalchemy.types.DateTime)
class sqlalchemy.dialects.sqlite.DATE
使用字符串在 SQLite 中表示 Python 日期对象。
默认的字符串存储格式为:
"%(year)04d-%(month)02d-%(day)02d"
例如:
2011-03-15
默认情况下,传入的存储格式将使用 Python 的 date.fromisoformat() 函数解析。
从版本 2.0 开始更改:默认日期字符串解析使用 date.fromisoformat()。
可以使用 storage_format 和 regexp 参数在一定程度上定制存储格式,例如:
import re from sqlalchemy.dialects.sqlite import DATE d = DATE( storage_format="%(month)02d/%(day)02d/%(year)04d", regexp=re.compile("(?P<month>\d+)/(?P<day>\d+)/(?P<year>\d+)") )
参数:
storage_format– 格式字符串,将应用于具有键年、月和日的字典。regexp– 将应用于传入结果行的正则表达式,以替换使用date.fromisoformat()来解析传入字符串。如果正则表达式包含命名组,则生成的匹配字典将作为关键字参数应用于 Python 的 date() 构造函数。否则,如果使用位置组,则通过*map(int, match_obj.groups(0))调用 date() 构造函数来传递位置参数。
类签名
class sqlalchemy.dialects.sqlite.DATE (sqlalchemy.dialects.sqlite.base._DateTimeMixin, sqlalchemy.types.Date)
class sqlalchemy.dialects.sqlite.JSON
SQLite JSON 类型。
SQLite 从版本 3.9 开始支持 JSON,通过其 JSON1 扩展。请注意,JSON1 是一个可加载扩展,因此可能不可用,或者可能需要运行时加载。
在 SQLite 后端中使用基本 JSON 数据类型时,JSON 会自动使用。
另请参阅
JSON - 通用跨平台 JSON 数据类型的主文档。
JSON 类型支持将 JSON 值持久化,以及通过在数据库级别包装 JSON_EXTRACT 函数并渲染为 JSON_QUOTE 函数来提供核心索引操作的 JSON 数据类型,以适应这些操作。提取的值都被引用,以确保结果始终是 JSON 字符串值。
版本 1.3 中的新功能。
成员
init()
类签名
class sqlalchemy.dialects.sqlite.JSON (sqlalchemy.types.JSON)
method __init__(none_as_null: bool = False)
继承自 JSON 的 sqlalchemy.types.JSON.__init__ 方法
构造一个 JSON 类型。
参数:
none_as_null=False –
如果为 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 意味着“没有默认值”。
此外,在 SQL 比较表达式中使用时,Python 值 None 仍然表示 SQL 空值,而不是 JSON NULL。JSON.none_as_null 标志显式指定了值在 INSERT 或 UPDATE 语句中的持久性。应该使用 JSON.NULL 值来表示希望与 JSON 空值进行比较的 SQL 表达式。
另请参阅
JSON.NULL
class sqlalchemy.dialects.sqlite.TIME
使用字符串在 SQLite 中表示 Python 时间对象。
默认字符串存储格式为:
"%(hour)02d:%(minute)02d:%(second)02d.%(microsecond)06d"
例如:
12:05:57.10558
默认情况下,传入的存储格式使用 Python 的 time.fromisoformat() 函数解析。
自 2.0 版本更改:默认时间字符串解析现在使用 time.fromisoformat()。
存储格式可以在一定程度上使用 storage_format 和 regexp 参数进行自定义,例如:
import re from sqlalchemy.dialects.sqlite import TIME t = TIME(storage_format="%(hour)02d-%(minute)02d-" "%(second)02d-%(microsecond)06d", regexp=re.compile("(\d+)-(\d+)-(\d+)-(?:-(\d+))?") )
参数:
storage_format– 将应用于包含小时、分钟、秒和微秒键的字典的格式字符串。regexp– 将应用于传入结果行的正则表达式,取代使用datetime.fromisoformat()解析传入字符串。如果正则表达式包含命名组,则结果匹配字典将作为关键字参数应用于 Python 的 time() 构造函数。否则,如果使用了位置组,则通过*map(int, match_obj.groups(0))将调用 time() 构造函数以传递位置参数。
类签名
class sqlalchemy.dialects.sqlite.TIME (sqlalchemy.dialects.sqlite.base._DateTimeMixin, sqlalchemy.types.Time)
SqlAlchemy 2.0 中文文档(五十)(3)https://developer.aliyun.com/article/1563129