繁体   English   中英

MySQL:对于表中的每一行,更改另一表中的一行

[英]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不会影响服务器在每个组中选择哪个值。

让我们将过程分为两个任务:

  1. 获取要更新data的行的id和设置c的值。
  2. 更新值。

任务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.

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