简体   繁体   English

具有自连接的困难的MySQL更新查询

[英]Difficult MySQL Update Query with Self-Join

Our website has listings. 我们的网站上有清单。 We use a connections table with the following structure to connect our members with these various listings: 我们使用具有以下结构的连接表将我们的成员与这些各种清单连接起来:

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`)
);

The problem we've run into is when we have to combine duplicate listings from time to time we also need to update our member connections and have been using the following query which breaks if a member is connected to both listings: 我们遇到的问题是,当我们不得不不时合并重复的列表时,我们还需要更新成员连接,并且一直在使用以下查询,如果一个成员同时连接到两个列表,该查询就会中断:

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

What I can't figure out is how to do the following which would solve this issue: 我不知道如何解决以下问题:

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
);

When I try to run that query I get the following error: 当我尝试运行该查询时,出现以下错误:

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

Here is some sample data. 这是一些示例数据。 Notice the update conflict for cid1 = 10025925 请注意,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                |
+----------+--------+------+---------------------+---------------------+

I'm hoping that someone can suggest the right way to run the above query. 我希望有人可以建议运行上述查询的正确方法。 Thanks in advance! 提前致谢!

One possible way would be to use a temporary table for your subquery then select from the temp table. 一种可能的方法是对子查询使用临时表,然后从临时表中选择。 Efficiency could break down fast if you need to execute a lot of these queires though. 但是,如果您需要执行许多此类查询,则效率可能会迅速下降。

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

And

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

The reason for the error in your query is because in MySQL you cannot SELECT from the table you are trying to UPDATE in the same query. 查询错误的原因是因为在MySQL中,您无法从试图在同一查询中进行更新的表中进行选择。

Use UPDATE IGNORE to avoid duplicate conflicts. 使用UPDATE IGNORE避免重复冲突。

I think you should try reading INSERT ON DUPLICATE KEY. 我认为您应该尝试阅读INSERT ON DUPLICATE KEY。 The idea is that you frame an INSERT query that always create a DUPLICATE conflict and then the UPDATE part will do its part. 这样的想法是,您对总是创建DUPLICATE冲突的INSERT查询进行构架,然后UPDATE部分将发挥其作用。

I was thinking something like the following, but I'm not 100% sure how your data looks before and after to determine accuracy. 我在想类似以下内容的方法,但是我不确定100%之前和之后的数据如何确定准确性。 The idea is to join the table to itself on your subquery's where clause and the exclusion where cid1 must not match. 想法是在子查询的where子句和排除cid1不能匹配的where将表自身连接起来。

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;

As near as I can tell, it'll work. 据我所知,它将起作用。 I used your create table (minus the cid3 in the primary key) and made sure I had 2 rows with the same cid1 and different cid2 (one 100000 and the other as 100001) and that the statement only affected 1 row. 我使用了您的create table (减去主键中的cid3 ),并确保我有2行具有相同的cid1和不同的cid2 (一个为100000,另一个为100001),并且该语句仅影响了1行。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM