简体   繁体   English

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

[英]MySQL: For each row in table, change one row in another table

I have two tables : 我有两个表:

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 |
+----+---+---+

and

SELECT * FROM changes;
+----+-------+-------+---+
| id | c_old | c_new | g |
+----+-------+-------+---+
|  1 |     1 |     2 | 2 |
|  2 |     2 |     1 | 3 |
|  3 |     1 |     2 | 2 |
+----+-------+-------+---+

For each row in changes I need to change exactly one row in data where data.g=changes.g and data.c=changes.c_old . 对于changes每一行,我需要只更改data.g=changes.g and data.c=changes.c_old一行data (assume that there will always be enough matches) (假设总会有足够的匹配项)

I'm attempting to do this with this query: 我正在尝试通过以下查询执行此操作:

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
)

Now, I'm surprised that that mess of a query runs at all. 现在,令我感到惊讶的是,一团糟的查询运行了。 But, it doesn't do what I need. 但是,它不能满足我的需求。 The innermost select returns this table: 最里面的选择返回此表:

+----+
| id |
+----+
|  1 |
|  6 |
|  1 |
+----+

Notice that 1 appears twice. 请注意1出现两次。 That means only two rows got changed (or row 1 got changed twice) when I needed three to change. 这意味着当我需要更改三行时,只有两行被更改(或第一行被更改了两次)。 Is there a way to make sure each id in that sub-query is unique? 有没有办法确保该子查询中的每个ID都是唯一的? Is there a better way to accomplish this mess? 有没有更好的方法来解决这个问题?

Thanks in advance! 提前致谢!

You are selecting a field that is not part of the group by or being aggregated. 您选择的字段不属于该组,也不属于该组。

SELECT data.id from 
data INNER JOIN changes ON
    data.c=changes.c_old AND data.g=changes.g 
GROUP BY changes.id

You should use an aggregate function on the data.id in the select, or add data.id to the groupby (though I suspect that is not the result you want either) 您应该在select中的data.id上使用聚合函数,或将data.id添加到groupby(尽管我怀疑那也不是您想要的结果)

The INNER JOIN is result in this dataset 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 are expanded out due to multiple matches in the join, and 4,5 are eliminated due to no match 由于连接中有多个匹配项,因此将1,2,3展开,由于没有匹配项而将4,5删除了

You then are grouping by changes.id, which is going to result in (showing with values in CSV list after grouping) 然后,您将按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 |
+---------+--------+--------+------------+---------------+---------------+-----------+

Since no aggregate or deterministic way of choosing the values from the available options, you are getting the 1 from data.id chosen for both changes.id 1 and 3 由于没有从可用选项中选择值的合计或确定性方式,因此将从为changes.id 1和3选择的data.id中获取1。

Depending on what you are wanting, are you wanting 3 rows? 根据您想要的内容,您是否需要3行? all distinct values? 所有不同的价值? you should add that deterministic behavior to the select. 您应该将确定性行为添加到选择中。

btw, I am pretty sure other SQL engines would not allow that select (such as MSSQL) because its ambiguous. 顺便说一句,我很确定其他SQL引擎将不允许该选择(例如MSSQL),因为它含糊不清。 As for MySQL behavior in that situation, I believe it chooses the first value from the first row stored, and thus why you probably get 1 in both cases, but it is free to choose whatever value it wishes. 至于在这种情况下的MySQL行为,我相信它会从存储的第一行中选择第一个值,因此为什么在两种情况下都可能获得1,但可以自由选择所需的任何值。

http://dev.mysql.com/doc/refman/5.7/en/group-by-extensions.html http://dev.mysql.com/doc/refman/5.7/en/group-by-extensions.html

MySQL extends the use of GROUP BY so that the select list can refer to nonaggregated columns not named in the GROUP BY clause. MySQL扩展了GROUP BY的使用,以便选择列表可以引用未在GROUP BY子句中命名的非聚合列。 This means that the preceding query is legal in MySQL. 这意味着前面的查询在MySQL中是合法的。 You can use this feature to get better performance by avoiding unnecessary column sorting and grouping. 您可以使用此功能来避免不必要的列排序和分组,从而获得更好的性能。 However, this is useful primarily when all values in each nonaggregated column not named in the GROUP BY are the same for each group. 但是,这主要在每个未聚合列中未在GROUP BY中命名的所有值对于每个组都相同时才有用。 The server is free to choose any value from each group, so unless they are the same, the values chosen are indeterminate. 服务器可以从每个组中自由选择任何值,因此,除非它们相同,否则选择的值是不确定的。 Furthermore, the selection of values from each group cannot be influenced by adding an ORDER BY clause. 此外,通过添加ORDER BY子句不会影响从每个组中选择值。 Sorting of the result set occurs after values have been chosen, and ORDER BY does not affect which values within each group the server chooses. 选择值之后,将对结果集进行排序,并且ORDER BY不会影响服务器在每个组中选择哪个值。

Let's divide the process into two tasks: 让我们将过程分为两个任务:

  1. Getting the id of the rows to update in data and the value to set c . 获取要更新data的行的id和设置c的值。
  2. Updating the values. 更新值。

Task 1 can be achieved by the following query (note the use of distinct to get rid of duplicates): 任务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

This should give you the following: 这应该给您以下内容:

| id | c_new |
|----|-------|
|  1 |     2 |
|  2 |     2 |
|  3 |     2 |
|  6 |     1 |
|  7 |     1 |

Now for the update just use the previous query as a derived table expression and join it to data : 现在,对于更新,只需将先前的查询用作派生表表达式并将其联接到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;

And you are done, final result: 至此,最终结果是:

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

相关问题 对于一个表中的每一行只有一行来自另一个表(mysql) - For each row from one table only one row from another table (mysql) MySQL:在一个表中为包含特定日期的另一表中的每一行查找最新行 - MySQL: Find most recent row in one table for each row in another table containing a specific date 如何验证表的每一行是否与 MySQL 中另一个表的至少一行相关联? - how can I verify that each row of a table is associated with at least one row of another table in MySQL? 从mysql中的另一个表加入一行 - join one row from another table in mysql MYSQL 为每一行从另一个表中加入随机行 - MYSQL join random row from another table for each row 如果一个字段在另一个表中,则检查每行的 Mysql 使用,如果不是删除该行 - Mysql for each row check to use if a field is in another table and if not delete that row 在另一张表中保留/分配新行,并在其中添加每一行 - Reserve/Assign a new row in another table with each row added in one MySQL-更改一行的时间值以匹配同一表的另一行的时间值 - MySQL - change time values of one row to match time values of another row of the same table 如何将一行从一个表移动到mysql中的另一个表? - How to move one row from one table, to another table in mysql? 将一个表的每一列作为一行插入到另一个表中 - Insert each column of one table as a row in another table
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM