![](/img/trans.png)
[英]IntegrityError: distinguish between unique constraint and not null violations
[英]pysqlite's IntegrityError: distinguish 'NOT NULL' from 'UNIQUE' violation
在pysqlite中,违反NOT NULL
或UNIQUE
约束同样会引发IntegrityError。 不幸的是,此Exception类型不提供错误代码,而只提供消息。
所以,假设我想忽略唯一约束违规,因为我知道这对给定数据是安全的,但是应该报告关键列中的Null值。
我想出了以下解决方案:
con = sqlite3.connect(':MEMORY:')
con.execute('''CREATE TABLE ABCD (A TEXT NOT NULL,
B TEXT NOT NULL,
C TEXT NOT NULL,
D TEXT NOT NULL,
PRIMARY KEY (A, B))''')
with con:
for a, b, c, d in inputs:
try:
con.execute('INSERT INTO ABCD VALUES (?, ?, ?, ?)',
(a, b, c, d))
except sqlite3.IntegrityError as e:
# Skip 'not unique' errors, but raise others.
if not e.message.endswith('not unique'):
raise
con.close()
但是,解析错误消息似乎是错误的,可能不可靠。 有没有更好的方法来做到这一点,甚至可能使用con.executemany()
?
这就是我最终做的事情:
con = sqlite3.connect(':MEMORY:')
con.execute('''CREATE TABLE ABCD (A TEXT NOT NULL,
B TEXT NOT NULL,
C TEXT NOT NULL,
D TEXT NOT NULL,
PRIMARY KEY (A, B))''')
with con:
for a, b, c, d in inputs:
if any(elem is None for elem in (a, b, c, d)):
raise ValueError('Fields must not be empty.')
con.execute('INSERT OR IGNORE INTO ABCD VALUES (?, ?, ?, ?)',
(a, b, c, d))
con.close()
像这样,在执行DB操作之前,“手动”捕获空值。 如果在execute
期间发生任何错误(例如违反UNIQUE
约束),则跳过该条目。 请注意, INSERT OR IGNORE
并不意味着忽略唯一性约束,而是忽略(即跳过)输入行。
此解决方案的缺点是检查空值两次。 我想这不是太糟糕,因为它可能是相当便宜的操作。 我认为,它仍然比解析错误消息更清晰,并且可能对更改更加健壮(例如pysqlite更新,这可能会更改错误消息中的某些细节)。
致谢:这个想法来自与Lutz的讨论。 它也是Martijn独立提出的。
更优雅的解决方案是完全依赖SQL(ite)功能。 通过为主键指定冲突子句( ON CONFLICT IGNORE
),已经实现了所需的行为:
con = sqlite3.connect(':memory:')
con.execute('''CREATE TABLE ABCD (A TEXT NOT NULL,
B TEXT NOT NULL,
C TEXT NOT NULL,
D TEXT NOT NULL,
PRIMARY KEY (A, B) ON CONFLICT IGNORE)''')
因此,静默跳过重复行(违反主键的唯一性约束),而Null值导致中止(导致sqlite3
异常)。 这一切都是在没有预先过滤Null / None值的数据或摆弄sqlite3
API的错误消息的情况下实现的。 我们现在可以简单地调用con.executemany()
,而con.executemany()
:
with con:
con.executemany('INSERT INTO ABCD VALUES (?, ?, ?, ?)', inputs)
以下是工作代码:
import sqlite3
con = sqlite3.connect(':memory:')
con.execute('''CREATE TABLE ABCD (A TEXT NOT NULL,
B TEXT NOT NULL,
C TEXT NOT NULL,
D TEXT NOT NULL,
PRIMARY KEY (A, B));''')
inputs = [('cow', 'pig', 'cat', 'dog'), ('cow', 'pig', 'quail', 'turkey')]
with con:
for a, b, c, d in inputs:
try:
con.execute('INSERT INTO ABCD VALUES (?, ?, ?, ?);',
(a, b, c, d))
except sqlite3.IntegrityError as e:
if 'not null' in e.args[0].lower():
print('There is a NULL value')
elif 'unique constraint' in e.args[0].lower():
print('There is unique violation')
else:
raise
测试:
>>>
There is a NULL value
>>>
第二次测试结果:
>>>
There is unique violation
>>>
希望,可以帮助你。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.