[英]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.