[英]MySQL: For each row in table, change one row in another table
我有两个表:
SELECT * FROM data;
+----+---+---+
| id | c | g |
+----+---+---+
| 1 | 1 | 2 |
| 2 | 1 | 2 |
| 3 | 1 | 2 |
| 4 | 1 | 3 |
| 5 | 2 | 2 |
| 6 | 2 | 3 |
| 7 | 2 | 3 |
+----+---+---+
和
SELECT * FROM changes;
+----+-------+-------+---+
| id | c_old | c_new | g |
+----+-------+-------+---+
| 1 | 1 | 2 | 2 |
| 2 | 2 | 1 | 3 |
| 3 | 1 | 2 | 2 |
+----+-------+-------+---+
对于changes
每一行,我需要只更改data.g=changes.g and data.c=changes.c_old
一行data
。 (假设总会有足够的匹配项)
我正在尝试通过以下查询执行此操作:
UPDATE
data INNER JOIN changes ON
data.c=changes.c_old AND p.g=changes.g
SET data.c_id=changes.c_new
WHERE data.id IN(
SELECT id FROM (
SELECT data.id from
data INNER JOIN changes ON
data.c=changes.c_old AND data.g=changes.g
GROUP BY changes.id
) AS another_table
)
现在,令我感到惊讶的是,一团糟的查询运行了。 但是,它不能满足我的需求。 最里面的选择返回此表:
+----+
| id |
+----+
| 1 |
| 6 |
| 1 |
+----+
请注意1
出现两次。 这意味着当我需要更改三行时,只有两行被更改(或第一行被更改了两次)。 有没有办法确保该子查询中的每个ID都是唯一的? 有没有更好的方法来解决这个问题?
提前致谢!
您选择的字段不属于该组,也不属于该组。
SELECT data.id from
data INNER JOIN changes ON
data.c=changes.c_old AND data.g=changes.g
GROUP BY changes.id
您应该在select中的data.id上使用聚合函数,或将data.id添加到groupby(尽管我怀疑那也不是您想要的结果)
INNER JOIN是此数据集中的结果
+---------+--------+--------+------------+---------------+---------------+-----------+
| data.id | data.c | data.g | changes.id | changes.c_old | changes.c_new | changes.g |
+---------+--------+--------+------------+---------------+---------------+-----------+
| 1 | 1 | 2 | 1 | 1 | 2 | 2 |
| 1 | 1 | 2 | 3 | 1 | 2 | 2 |
| 2 | 1 | 2 | 1 | 1 | 2 | 2 |
| 2 | 1 | 2 | 3 | 1 | 2 | 2 |
| 3 | 1 | 2 | 1 | 1 | 2 | 2 |
| 3 | 1 | 2 | 3 | 1 | 2 | 2 |
| 6 | 2 | 3 | 2 | 2 | 1 | 3 |
| 7 | 2 | 3 | 2 | 2 | 1 | 3 |
+---------+--------+--------+------------+---------------+---------------+-----------+
由于连接中有多个匹配项,因此将1,2,3展开,由于没有匹配项而将4,5删除了
然后,您将按changes.id分组,这将导致(分组后在CSV列表中显示值)
+---------+--------+--------+------------+---------------+---------------+-----------+
| data.id | data.c | data.g | changes.id | changes.c_old | changes.c_new | changes.g |
+---------+--------+--------+------------+---------------+---------------+-----------+
| 1,2,3 | 1,1,1 | 2,2,2 | 1 | 1,1,1 | 2,2,2 | 2,2,2 |
| 1,2,3 | 1,1,1 | 2,2,2 | 3 | 1,1,1 | 2,2,2 | 2,2,2 |
| 6,7 | 2,2 | 3,3 | 2 | 2,2 | 1,1 | 3,3 |
+---------+--------+--------+------------+---------------+---------------+-----------+
由于没有从可用选项中选择值的合计或确定性方式,因此将从为changes.id 1和3选择的data.id中获取1。
根据您想要的内容,您是否需要3行? 所有不同的价值? 您应该将确定性行为添加到选择中。
顺便说一句,我很确定其他SQL引擎将不允许该选择(例如MSSQL),因为它含糊不清。 至于在这种情况下的MySQL行为,我相信它会从存储的第一行中选择第一个值,因此为什么在两种情况下都可能获得1,但可以自由选择所需的任何值。
http://dev.mysql.com/doc/refman/5.7/en/group-by-extensions.html
MySQL扩展了GROUP BY的使用,以便选择列表可以引用未在GROUP BY子句中命名的非聚合列。 这意味着前面的查询在MySQL中是合法的。 您可以使用此功能来避免不必要的列排序和分组,从而获得更好的性能。 但是,这主要在每个未聚合列中未在GROUP BY中命名的所有值对于每个组都相同时才有用。 服务器可以从每个组中自由选择任何值,因此,除非它们相同,否则选择的值是不确定的。 此外,通过添加ORDER BY子句不会影响从每个组中选择值。 选择值之后,将对结果集进行排序,并且ORDER BY不会影响服务器在每个组中选择哪个值。
让我们将过程分为两个任务:
data
的行的id
和设置c
的值。 任务1可以通过以下查询来完成(请注意使用distinct
来消除重复项):
select distinct d.id, c.c_new
from
data as d
inner join changes as c
on d.c = c.c_old
and d.g = c.g
这应该给您以下内容:
| id | c_new |
|----|-------|
| 1 | 2 |
| 2 | 2 |
| 3 | 2 |
| 6 | 1 |
| 7 | 1 |
现在,对于更新,只需将先前的查询用作派生表表达式并将其联接到data
:
update
data as da
inner join (
select distinct d.id, c.c_new
from
data as d
inner join changes as c
on d.c = c.c_old
and d.g = c.g
) as dc
on da.id = dc.id
set d.c = dc.c_new;
至此,最终结果是:
| ID | C | G |
|----|---|---|
| 1 | 2 | 2 |
| 2 | 2 | 2 |
| 3 | 2 | 2 |
| 4 | 1 | 3 |
| 5 | 2 | 2 |
| 6 | 1 | 3 |
| 7 | 1 | 3 |
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.