Перемещение строк между таблицами в SQL

У меня есть 2 таблицы, активная таблица и неактивная таблица. Я хочу, чтобы строки переехать из активной таблицы в неактивную. Моя первая мысль была

insert into inactive select * from active where ...
delete from active active where ...

Однако примерно через 0,42 секунды я заметил, что это приведет к удалению / дублированию строк, если обновления изменят то, что выбирает предложение where.

В этом случае я легко могу это предотвратить, но что мне делать, если я не могу?

edit: Из ответов похоже, что нет простого / тривиального способа сделать это. Я действительно удивлен этим. Я думаю, что это принесет существенные выгоды.

ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
5
0
9 410
8
Перейти к ответу Данный вопрос помечен как решенный

Ответы 8

Ответ принят как подходящий

Флаги статуса - ваш друг.

UPDATE old_data SET move = "MARKED";
INSERT INTO somewhere... SELECT where move = "MARKED";
DELETE FROM old_data WHERE move = "MARKED";

Если вы сделаете это с выключенным Autocommit, он повсюду захватит блокировки.

Вы можете COMMIT после каждого шага, если хотите немного меньше блокировать.

Вроде для этого нужен FTS3? Получил Error: no such module: FTS3. Я не могу найти двоичный файл sqlite3 для Android с FTS3 ...

Luis A. Florit 22.10.2015 23:07

(По крайней мере, в MS SQL) вы можете использовать транзакции и подсказки блокировки:

begin tran

insert into inactive
select * from active with (updlock)
where ...

delete from active
where ...

commit tran

Без указания блокировки (обновления) могут возникнуть взаимоблокировки, если кто-то изменит удаляемые записи.

Извините, я ничего не знаю о sqlite, но у меня Error: near "(": syntax error

Luis A. Florit 22.10.2015 21:37

@ LuisA.Florit - где я сказал "sqlite"? Мой совет будет работать в MS SQL Server, скорее всего, есть аналогичные возможности в Oracle и других серверах sql, но синтаксис может отличаться. SQLite имеет несколько ограниченную функциональность; поддерживает ли он транзакции и подсказки запросов, я не знаю. Из вашего комментария я бы сказал, что подсказки не поддерживаются.

Arvo 23.10.2015 09:53

Если вы можете заблокировать строки пессимистически, то есть когда вы читаете их, чтобы скопировать их в неактивную таблицу, тогда никто не сможет изменить их из-под вас.

Метод блокировки строк зависит от марки базы данных, и вы не указываете это в своем вопросе.

Объявите локальную таблицу var и поместите в нее значения, вставьте их в неактивную таблицу, затем удалите строки из активной таблицы, которые находятся в вашем локальном списке.

Однако идея транзакции тоже работает.

Либо используйте уникальный столбец идентификатора, например

delete from active where rowid in (select rowid in inactive)

или же

delete from active as a 
where exists (select * 
              from inactive 
              where pkfld1=a.pkfld1 
              and pkfld2=a.pkfld2)

Также не забудьте обернуть этот процесс транзакцией.

Удачи.

EXISTS не совсем специфичен для MS SQL Server - это стандарт SQL-92, и я верю, что он также используется в MySQL и Oracle (кто-нибудь поправит меня, если я ошибаюсь).

Ian Varley 19.11.2008 03:20

хммм ... похоже, вы правы. contrib.andrew.cmu.edu/~shadow/sql/sql1992.txt

John MacIntyre 19.11.2008 16:13

Вот как я сохраняю свои предложения where:

DECLARE @MyTable TABLE
(
  TheKey int PRIMARY KEY
)
--
INSERT INTO @MyTable(TheKey)
SELECT TheKey FROM SourceTable WHERE rows I want
--
INSERT INTO Inactive(fieldlist)
SELECT fieldlist
FROM Active
WHERE TheKey IN (SELECT TheKey FROM @MyTable)
--
DELETE
FROM Active
WHERE TheKey IN (SELECT TheKey FROM @MyTable)

Если вам нужно более сильное, вам нужно посмотреть на блокировку (заблокировать изменения во время транзакции).

Почему у вас две таблицы, а не столбец для IsActive?

Производительность, связанная с размером таблицы. Это одно только IIRC может быть хорошей причиной.В моих случаях из-за того, как я его использую, если запрос делает что-либо, но / поиск по индексу, он / превратится в поиск наихудших случаев (вроде как здесь en.wikipedia.org/wiki/Linear_probing )

BCS 19.11.2008 01:17

Также: «Я никогда больше не буду использовать этот код, так зачем исправлять то, что в основном работает» ;-)

BCS 19.11.2008 01:18

ОК, согласился. Теперь мы обсуждаем одно из последствий. Другой - неизбежный «найти записи ГДЕ ...», и они могут быть в любой таблице. Возникает резонный вопрос: «Оказывается, это лучший способ справиться с проблемами производительности, связанными с размером таблицы?» Вот почему я спрашиваю.

dkretz 19.11.2008 02:11

Неужели таблица настолько огромна, что SQL Server не может достаточно эффективно хранить и извлекать индексы? Представленный вопрос не предполагает такого глубокого понимания технологии.

dkretz 19.11.2008 02:16

Поддерживает ли ваша база данных пункт OUTPUT? Тогда это могло бы быть идеальным и простым решением для вас, не так ли?

http://msdn.microsoft.com/en-us/library/ms177564.aspx

delete active with (readpast)
output DELETED.*
into inactive
where ...

Я должен буду проверить, но если это произойдет, это ТОЧНО то, что я искал !! (MySQL на случай, если кто-то доберется до меня раньше, чем я.)

BCS 20.11.2008 01:30

А как насчет триггеров? В SQL Server я выполнил аналогичную задачу с триггером на удаление, который вставлял удаленные сообщения в таблицу истории.

Örjan Jämte 20.11.2008 19:11

Другие вопросы по теме