SQLinfo.ru - Все о MySQL

Форум пользователей MySQL

Задавайте вопросы, мы ответим

Вы не зашли.

#1 29.05.2009 01:11:16

rulan
Участник
Зарегистрирован: 28.05.2009
Сообщений: 2

Как лучше выполнить UPDATE при наличии duplicated keys

Привет!
Имеется таблица:

CREATE TABLE `or_participate_at` (
  `participate_id` int(20) NOT NULL auto_increment,
  `participant_id` int(20) default NULL,
  `experiment_id` int(20) default NULL,
  `invited` char(1) default 'n',
  `registered` char(1) default 'n',
  `shownup` char(1) default 'n',
  `participated` char(1) default 'n',
  `session_id` int(20) default '0',
  PRIMARY KEY  (`participate_id`),
  UNIQUE KEY `uindex` (`participate_id`),
  UNIQUE KEY `uindex2` (`participant_id`,`experiment_id`),
  KEY `tindex` (`session_id`),
  KEY `tindex2` (`experiment_id`),
  KEY `tindex3` (`participant_id`),
  KEY `tindex4` (`session_id`,`registered`),
  KEY `tindex5` (`experiment_id`,`invited`),
  KEY `tindex6` (`experiment_id`,`shownup`),
  KEY `tindex7` (`experiment_id`,`participated`),
  KEY `tindex8` (`session_id`,`participated`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;


Чтобы было понятнее, таблица отражет историю участия в экспериментах (`experiment_id`) участников (`participant_id`). Каждый участник может участвовать в одном из экспериментов лишь один раз (UNIQUE KEY `uindex2` (`participant_id`,`experiment_id`)). Поля `invited`, `registered`, `shownup` и `participated`отражают этапы участия в эксперименте  - приглашение, регистрация, посещение, участие. Вышеперечисленные поля заполняются по порядку событий начиная с `invited`. Скажем, участник не может быть только `shownup`='y', если `shownup` стоит в значении 'y' значит и предыдущие два поля тоже в 'y'. Предположим для некоторых участников по ошибке была создана еще одна учетная запись со своим уникальным `participant_id`, некоторое время она просуществовала и имеет историю участия. При выявлении такого случая вся история должна комбинироваться в одну из учетных записей, после чего пустая (без истории) учетная запись удаляться.

Проблема в том что за обе учетные записи могут иметь историю участия в одних и тех же экспериментах, таким образом простое решение
UPDATE IGNORE or_participate_at set participant_id = 400711420 where participant_id = 1979714289;
сделает только половину работы и не изменит записи с совпадающим `experiment_id`. Критерий же объединения таких записей лежит в полях `invited`, `registered`, `shownup` и `participated`отражающих этапы участия от приглашения до участия - должна сохраниться та запись где больше информации в этих полях а другие удалиться.

132412, 400711420, 1503025322, 'y', 'n', 'n', 'n', 0
141488, 400711420, 1453000548, 'y', 'y', 'n', 'n', 0
133685, 1979714289, 1503025322, 'y', 'y', 'y', 'y', 581435840
139654, 1979714289, 1453000548, 'y', 'y', 'y', 'y', 47490904

В таком примере должны сохраниться записи '133685' и '139654', а '132412' и '141488' удалены.

Я вижу решение этой задачи следующим образом:

1. Делаю выборку дублирующихся записей (для примеры выше):

select t1.* from or_participate_at as t1, (select experiment_id, count(experiment_id) as cnt_exp from or_participate_at where participant_id in (1979714289,400711420) group by experiment_id) as t2 where participant_id in (1979714289,400711420) and t1.experiment_id = t2.experiment_id and t2.cnt_exp > 1


Разбираю ее на стороне клиента, вычисляю какая из повторяющихся записей имеет наибольший вес (более информативная по числу полей с 'y'), и удаляю записи с меньшим весом (для примера выше '132412' и '141488' будут удалены).

2. Выполняю
UPDATE or_participate_at set participant_id = 400711420 where participant_id = 1979714289;
который должен выполниться гладко ввиду отсутствия дублирующихся ключей, но и наконец удаляю саму учетную запись из соответствующей таблицы.

Вопрос - существует ли более оптимальное решение этой задачи? Спасибо! wink

Отредактированно rulan (29.05.2009 01:12:58)

Неактивен

 

#2 29.05.2009 02:55:00

paulus
Администратор
MySQL Authorized Developer and DBA
Зарегистрирован: 22.01.2007
Сообщений: 6757

Re: Как лучше выполнить UPDATE при наличии duplicated keys

А почему у Вас такой странный способ хранения информации? Кажется, поле
state enum (unknown, invited, ... participated) будет логичнее отражать Ваши сложные
связи буковок y/n (и к тому же нельзя будет участвовать и не пригласиться заранее).
В новой схеме, очевидно, нужно будет выбрать просто запись с самым большим state.

Что касается задачи в целом, то, кажется, достаточно создать временную табличку
без уникального ключа, выкинуть в нее все строки от обоих участников, обновить в
ней id участника на какой-то один, и потом залить назад с группировкой по экспери-
менту и с MAX() по остальным полям.

Неактивен

 

#3 29.05.2009 19:46:06

rulan
Участник
Зарегистрирован: 28.05.2009
Сообщений: 2

Re: Как лучше выполнить UPDATE при наличии duplicated keys

Насчет странности в организации таблицы полностью согласен, но это было создано задолго до того как я взялся за этот проект на досуге может поменяю, хотя очень много всего уже завязано на такую организацию. Спасибо за совет!

Неактивен

 

Board footer

Работает на PunBB
© Copyright 2002–2008 Rickard Andersson