Сложный MySQL Update Query с Self-Join - PullRequest
2 голосов
/ 17 июня 2011

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

CREATE TABLE `connections` (
  `cid1` int(9) unsigned NOT NULL DEFAULT '0',
  `cid2` int(9) unsigned NOT NULL DEFAULT '0',
  `type` char(2) NOT NULL,
  `created` datetime DEFAULT NULL,
  `updated` datetime DEFAULT NULL,
  PRIMARY KEY (`cid1`,`cid2`,`type`,`cid3`),
  KEY `cid1` (`cid1`,`type`),
  KEY `cid2` (`cid2`,`type`)
);

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

update connections set cid2=100000
where type IN ('MC','MT','MW') AND cid2=100001;

Что я не могу понять, это как сделать следующее, что решило бы эту проблему:

update connections set cid2=100000
where type IN ('MC','MT','MW') AND cid2=100001 AND cid1 NOT IN (
    select cid1 from connections
    where type IN ('MC','MT','MW') AND cid2=100000
);

Когда я пытаюсь выполнить этот запрос, я получаю следующую ошибку:

ERROR 1093 (HY000): You can't specify target table 'connections' for update in FROM clause

Вот некоторые примеры данных.Обратите внимание на конфликт обновлений для cid1 = 10025925

+----------+--------+------+---------------------+---------------------+
| cid1     | cid2   | type | created             | updated             |
+----------+--------+------+---------------------+---------------------+
| 10010388 | 100000 | MC   | 2010-08-05 18:04:51 | 2011-06-16 16:26:17 |
| 10025925 | 100000 | MC   | 2010-10-31 09:21:25 | 2010-10-31 16:21:25 |
| 10027662 | 100000 | MC   | 2011-06-13 16:31:12 | NULL                |
| 10038375 | 100000 | MW   | 2011-02-05 05:32:35 | 2011-02-05 19:51:58 |
| 10065771 | 100000 | MW   | 2011-04-24 17:06:35 | NULL                |
| 10025925 | 100001 | MC   | 2010-10-31 09:21:45 | 2010-10-31 16:21:45 |
| 10034884 | 100001 | MC   | 2011-01-20 18:54:51 | NULL                |
| 10038375 | 100001 | MC   | 2011-02-04 05:00:35 | NULL                |
| 10041989 | 100001 | MC   | 2011-02-26 09:33:18 | NULL                |
| 10038259 | 100001 | MC   | 2011-05-07 13:34:20 | NULL                |
| 10027662 | 100001 | MC   | 2011-06-13 16:33:54 | NULL                |
| 10030855 | 100001 | MT   | 2010-12-31 20:40:18 | NULL                |
| 10038375 | 100001 | MT   | 2011-02-04 05:00:36 | NULL                |
+----------+--------+------+---------------------+---------------------+

Я надеюсь, что кто-то может предложить правильный способ выполнения вышеуказанного запроса.Заранее спасибо!

Ответы [ 4 ]

2 голосов
/ 17 июня 2011

Причина ошибки в вашем запросе в том, что в MySQL вы не можете ВЫБРАТЬ из таблицы, которую вы пытаетесь ОБНОВИТЬ в том же запросе.

Используйте UPDATE IGNORE, чтобы избежать дублирующихся конфликтов.

Я думаю, что вы должны попробовать прочитать INSERT ON DUPLICATE KEY.Идея состоит в том, что вы создаете запрос INSERT, который всегда создает конфликт DUPLICATE, и тогда часть UPDATE выполнит свою роль.

2 голосов
/ 17 июня 2011

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

create temporary table subq as select cid1 from connections where type IN ('MC','MT','MW') AND cid2=100000

И

update connections set cid2=100000 where type IN ('MC','MT','MW') AND cid2=100001 AND cid1 NOT IN (select cid1 from subq);
1 голос
/ 17 июня 2011
UPDATE connections cn1
LEFT JOIN connections cn2 ON cn1.cid1 != cn2.cid1
    AND cn2.type IN ('MC','MT','MW')
    AND cn2.cid2=100000
SET cn1.cid2=100000
WHERE cn1.TYPE IN ('MC','MT','MW') 
    AND cn1.cid2=100001 
    AND cn2.cid1 IS NULL -- i.e. there is no matching record
1 голос
/ 17 июня 2011

Я думал примерно так, но я не уверен на 100%, как ваши данные выглядят до и после, чтобы определить точность.Идея состоит в том, чтобы объединить таблицу с самим собой в предложении where вашего подзапроса и исключении, где cid1 не должно совпадать.

update connections c1 left outer join connections c2
 on (c2.cid2 = 100000 and c2.type in ('MC','MT','MW') and c1.cid1 != c2.cid1)
 set c1.cid2 = 100000
 where c1.type in ('MC', 'MT', 'MW') and c1.cid2=100001 and c2.cid1 is null;

Насколько я могу судить, это будет работать.Я использовал ваш create table (минус cid3 в первичном ключе) и убедился, что у меня есть 2 строки с одинаковым cid1 и разными cid2 (один 100000 и другой как 100001), и что оператор влияет только1 ряд.

...