SQLite вставляет или игнорирует и возвращает исходный rowid
Я провел некоторое время, читая SQLite docs различные вопросы и ответы здесь, на переполнение стека, и эта штука, но не пришли к полному ответу.
Я знаю, что нет никакого способа, чтобы сделать что-то вроде INSERT OR IGNORE INTO foo VALUES(...)
С SQLite и вернуть rowid исходной строки, и что ближе всего к нему будет INSERT OR REPLACE
но это удаляет всю строку и вставляет новую строку и таким образом получает новый идентификатор rowid.
пример таблица:
CREATE TABLE foo(
id INTEGER PRIMARY KEY AUTOINCREMENT,
data TEXT
);
прямо сейчас я могу сделать:
sql = sqlite3.connect(":memory:")
# create database
sql.execute("INSERT OR IGNORE INTO foo(data) VALUES(?);", ("Some text.", ))
the_id_of_the_row = None
for row in sql.execute("SELECT id FROM foo WHERE data = ?", ("Some text.", )):
the_id_of_the_row = row[0]
но что-то идеально будет выглядеть так:
the_id_of_the_row = sql.execute("INSERT OR IGNORE foo(data) VALUES(?)", ("Some text", )).lastrowid
каков наилучший (читай: самый эффективный) способ вставить строку в таблицу и вернуть rowid или проигнорировать строку, если она уже существует, и просто получить rowid? эффективность важна, потому что это будет происходить довольно часто.
есть ли способ INSERT OR IGNORE
и возвращает rowid строки, которую игнорируется Роу сравнивали с? это было бы здорово, так как это было бы так же эффективно, как вставка.
2 ответов
способ, который работал лучше всего для меня было insert or ignore
значения, и select
rowid в два отдельных шага. Я использовал unique
ограничение data
столбец для ускорения выбирает и избегает дубликатов.
sql.execute("INSERT OR IGNORE INTO foo(data) VALUES(?);" ("Some text.", ))
last_row_id = sql.execute("SELECT id FROM foo WHERE data = ?;" ("Some text. ", ))
на select
утверждение не так медленно, как я думал. Это кажется, из-за SQLite автоматически создает индекс для unique
столбцы.
INSERT OR IGNORE
для ситуаций, когда вы не заботитесь о идентичности записи; где цель состоит только в том, чтобы иметь некоторые записи с конкретным значением.
если вы хотите знать, вставлена ли новая запись или нет, вы должны проверить вручную:
the_id_of_the_row = None
for row in sql.execute("SELECT id FROM foo WHERE data = ?", ...):
the_id_of_the_row = row[0]
if the_id_of_the_row is None:
c = sql.cursor()
c.execute("INSERT INTO foo(data) VALUES(?)", ...)
the_id_of_the_row = c.lastrowid
что касается эффективности: когда SQLite проверяет data
столбец для дубликатов, он должен делать точно такой же запрос, который вы делаете с SELECT
, и как только вы это сделаете, путь доступа в кэше, поэтому производительность не должны быть проблемой. Во всяком случае, это is необходимо выполнить два отдельных INSERT
/SELECT
запросы (в любом порядке, как ваш, так и мой код работают, но ваш проще).