【问题标题】:SQLite NOT NULL constraint not working with INSERT OR IGNORESQLite NOT NULL 约束不适用于 INSERT OR IGNORE
【发布时间】:2013-04-12 02:57:49
【问题描述】:

我使用 Python 2.7 和 SQLite3。

代码如下:

#!/usr/bin/env python

import sqlite3
conn = sqlite3.connect('example.db')
c = conn.cursor()
c.execute('''CREATE TABLE stocks
             (transctionid text not null collate nocase primary key,
             trans text,
             symbol text not null,
             qty real,
             price real)''')
purchases = [('B1Jan', 'BUY', 'IBM', 1000, 45.00),
             ('C2Jan', 'BUY', 'MSFT', 1000, 72.00),
             ('D3Jan', 'SELL', 'IBM', 500, 53.00),
             ('d3jan', 'SELL', 'IBM', 500, 53.00),
             ('', 'SELL', 'IBM', 500, 53.00),
             ('E5Jan', 'SELL', '', 500, 53.00),
            ]
c.executemany('INSERT OR IGNORE INTO stocks VALUES (?,?,?,?,?)', purchases)
conn.commit()
for row in c.execute('SELECT * FROM stocks ORDER BY price'):
    print row
conn.close()

结果是:

(u'B1Jan', u'BUY', u'IBM', 1000.0, 45.0)
(u'D3Jan', u'SELL', u'IBM', 500.0, 53.0)
(u'', u'SELL', u'IBM', 500.0, 53.0)
(u'E5Jan', u'SELL', u'', 500.0, 53.0)
(u'C2Jan', u'BUY', u'MSFT', 1000.0, 72.0)

INSERT OR IGNORE 仅适用于“PRIMARY KEY”约束。 “NOT NULL”约束不起作用。

根据http://www.sqlite.org/lang_conflict.html

对于 INSERT 和 UPDATE 命令,关键字“ON CONFLICT”是 用“OR”代替,这样语法读起来更自然。例如, 我们有“INSERT OR IGNORE”而不是“INSERT ON CONFLICT IGNORE”。 ... 这 ON CONFLICT 子句适用于 UNIQUE 和 NOT NULL 约束(以及 就本节而言,PRIMARY KEY 约束是 与 UNIQUE 约束相同)。

我预期的结果是:

(u'B1Jan', u'BUY', u'IBM', 1000.0, 45.0)
(u'D3Jan', u'SELL', u'IBM', 500.0, 53.0)
(u'C2Jan', u'BUY', u'MSFT', 1000.0, 72.0)

顺便问一下,我怎么知道哪一行插入成功,哪一行在冲突中被忽略?

【问题讨论】:

    标签: python sql python-2.7 sqlite


    【解决方案1】:

    空字符串不算NULL,而是0长度字符串。

    如果您希望插入 SQL NULL,请改用 None

    purchases = [('B1Jan', 'BUY', 'IBM', 1000, 45.00),
                 ('C2Jan', 'BUY', 'MSFT', 1000, 72.00),
                 ('D3Jan', 'SELL', 'IBM', 500, 53.00),
                 ('d3jan', 'SELL', 'IBM', 500, 53.00),
                 (None, 'SELL', 'IBM', 500, 53.00),
                 ('E5Jan', 'SELL', None, 500, 53.00),
                ]
    

    请参阅sqlit3 文档的SQLite and Python types 部分。

    如果需要知道行是否插入成功,用cursor.execute()一一插入,之后检查cursor.rowcount.rowcount 反映了受影响的行数,对于带有NULL 值的.executemany() 调用,行数为3,没有关于哪些行成功和哪些行失败的信息。

    【讨论】:

    • 顺便问一下,我怎么知道哪一行插入成功,哪一行在冲突中被忽略?
    • INSERT 一对一和 ROWCOUNT 的方法似乎非常无效且耗时。有没有更好的方法?
    • 不,没有。 OR IGNORE 文档明确表示没有错误,我们唯一的其他反馈是行数。
    【解决方案2】:

    '' 与 NULL 不同。将'' 替换为None

    如果您想知道哪些行违反了约束,请删除OR IGNORE 并处理sqlite3.IntegrityError。下面的代码示例会一一插入行并打印(可以修改为写入文件、记录错误表等),以便您知道哪些值无法插入以及原因:

    import sqlite3
    conn = sqlite3.connect('example.db')
    c = conn.cursor()
    c.execute('''CREATE TABLE stocks
                 (transctionid text not null collate nocase primary key,
                 trans text,
                 symbol text not null,
                 qty real,
                 price real)''')
    purchases = [('B1Jan', 'BUY', 'IBM', 1000, 45.00),
                 ('C2Jan', 'BUY', 'MSFT', 1000, 72.00),
                 ('D3Jan', 'SELL', 'IBM', 500, 53.00),
                 ('d3jan', 'SELL', 'IBM', 500, 53.00),
                 (None, 'SELL', 'IBM', 500, 53.00),
                 ('E5Jan', 'SELL', None, 500, 53.00)]
    for purchase in purchases:
        try:
            c.execute('INSERT INTO stocks VALUES (?,?,?,?,?)', purchase)
        except sqlite3.IntegrityError as e:
            print "Couldn't insert row {}:\n {}".format(purchase, e)
            pass
    conn.commit()
    for row in c.execute('SELECT * FROM stocks ORDER BY price'):
        print row
    conn.close()
    

    【讨论】:

    • 顺便问一下,我怎么知道哪一行插入成功,哪一行在冲突中被忽略?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-05
    • 2021-09-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多