Как я могу вставить данные и удалить повторяющиеся строки с помощью одной команды SQL - PullRequest
0 голосов
/ 11 октября 2018

Каков наилучший способ вставки данных в таблицу одновременно с удалением, если в таблице есть повторяющиеся записи?Существует способ сохранить дублированные идентификаторы данных во временной таблице, а затем удалить их.Но это не эффективный способ сделать это.Любая лучшая идея будет оценена.

МОЙ СТОЛ

CREATE TABLE account(  
  user_id serial PRIMARY KEY,  
  username VARCHAR(50) UNIQUE NOT NULL,  
  password VARCHAR (50) NOT NULL,  
  email VARCHAR(355) UNIQUE NOT NULL,  
  created_on TIMESTAMP NOT NULL,  
  last_login TIMESTAMP 
);

Ответы [ 2 ]

0 голосов
/ 11 октября 2018

«Немедленным» ответом было бы просто запустить оператор DELETE, а затем выполнить оператор INSERT в одной транзакции.

Если вы хотите, например, избегать повторяющихся имен пользователей, тогда вы можете сделать что-то вроде этого:

begin transaction
  delete from account
  where username = 'arthur';

  insert into account(username, password, email, created_on)
  values ('arthur', '****', 'arthur@h2g2.com', current_timestamp);
commit;

Вы можете объединить это в одно утверждение, но это не такЭто не имеет большого значения:

with new_values (username, password, email, created_on) as (
  values values ('arthur', '****', 'arthur@h2g2.com', current_timestamp);
), deleted as (
  delete from the_table 
  where username = (select username from new_values)
) 
insert into account
select *
from new_values;

Единственное преимущество в том, что вам не нужно повторять значения дважды.

Однако, если на account ссылаются другие таблицы (т. Е. Внешний ключ «указывает» на the_table), это не будет работать, так как DELETE не будет работать, если на строку все еще ссылаются.

Лучшее решение состоит в том, чтобы использовать INSERT ON CONFLICT и затем обновить существующую строку новыми данными:

insert into account(username, password, email, created_on)
values ('arthur', '****', 'arthur@h2g2.com', current_timestamp)
on conflict (username) 
do update 
  set password = excluded.password, 
      email = excluded.email;

Однако это все равно выдаст ошибку, если электронное письмо уже существует, но, к сожалению,для on conflict do update можно указать только одно уникальное ограничение.

Чтобы справиться с двумя различными уникальными ограничениями, все становится немного сложнее:

with new_values (username, password, email, created_on) as (
  values 
    ('arthur', '***', 'arthur@h2g2.com', current_timestamp)
), inserted as (
  insert into account(username, password, email, created_on)
  select * from new_values
  on conflict do nothing
  returning id
)
update account
  set password = nv.password
from new_values nv  
where (account.username = nv.username or account.email = nv.email)
  and not exists (select * from inserted); 

Сначала делается попытка вставки.Если какое-либо уникальное ограничение нарушается, вставка просто игнорируется (on conflict do nothing).

Окончательный оператор UPDATE выполняется только в том случае, если на предыдущем шаге не было вставлено ни одной строки.Это достигается с помощью and not exists (select * from inserted.

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

0 голосов
/ 11 октября 2018

Я думаю, что действительно простой способ сделать это - добавить уникальный индекс для определенных столбцов.Когда вы пишете оператор ALTER, включите ключевое слово IGNORE.Вот так:

ALTER IGNORE TABLE orders ADD UNIQUE INDEX idx_name (col1, col2, col3, others);

Это удалит все повторяющиеся строки.В качестве дополнительного преимущества будущие вставки, которые являются дубликатами, будут ошибаться.Как всегда, вы можете сделать резервную копию, прежде чем запускать что-то вроде этого ...

Надеюсь, это поможет вам.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...