13

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()ますか?

4

3 に答える 3

3

これは私がやったことです:

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これは、一意性制約を無視するという意味ではなく、入力行を無視する (つまり、スキップする) ことを意味することに注意してください。

このソリューションの欠点は、空の値のチェックが 2 回行われることです。ただし、これはおそらくかなり安価な操作であるため、それほど悪くはないと思います。エラーメッセージを解析するよりもまだクリーンであり、おそらく変更に対してより堅牢であると思います(エラーメッセージの詳細が変更される可能性のあるpysqliteの更新など)。

クレジット: このアイデアは、ルッツとの話し合いから生まれました。これは Martijn によって独立して提案されました。

于 2014-06-26T08:04:08.340 に答える
1

より洗練されたソリューションは、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 値のデータを事前にフィルタリングしたり、sqlite3API のエラー メッセージをいじったりすることなく実現されます。これで簡単に を呼び出すことができますcon.executemany()

with con:
    con.executemany('INSERT INTO ABCD VALUES (?, ?, ?, ?)', inputs)
于 2015-08-08T20:17:53.337 に答える