guigoz
guigoz

Reputation: 704

SQL statement: how can I pick a value only once from a table to update another table?

I wish to update table1 with any distinct value of table2 matching the same code, no matter which one or the order (value from table2 can't be picked more than once)

+-------------------+      +--------------+
|      table1       |      |    table2    |
+-------------------+      +--------------+
| id | code | value |      | code | value |
+----+------+-------+      +------+-------+
| 1  |  A   |       | <--  |  A   |  v1   |
| 2  |  A   |       |      |  B   |  v2   |
| 3  |  B   |       |      |  A   |  v3   |
+----+------+-------+      |  A   |  v5   |
                           |  A   |  v6   |
                           +------+-------+
+-------------------+                      
|      table1       |                      
+-------------------+                      
| id | code | value |
+----+------+-------+
| 1  |  A   |  v6   |
| 2  |  A   |  v3   |
| 3  |  B   |  v2   |
+----+------+-------+

How can I write the SQL update statement ? (MySQL 5.7)

Upvotes: 1

Views: 64

Answers (4)

guigoz
guigoz

Reputation: 704

The statement provided by Madhur Bhaiya does work if

  1. @rn* are initialized to 1 instead of 0 (otherwise row_num* are numbered 1 twice)
  2. the SELECT from table2 is DISTINCT (because pairs of (code,value) are repeated in table2)

The statement should be

UPDATE 
table1 AS t1 

JOIN 

(SELECT 
   dt1.id, 
   IF(@cd1 = dt1.code, @rn1 := @rn1 + 1, 1) AS row_num1, 
   @cd1 := dt1.code AS code,
 FROM (SELECT id, code FROM table1 ORDER BY code, id) AS dt1
 CROSS JOIN (SELECT @rn1 := 1, @cd1 := '') AS init1
) AS t2 
  ON t2.id = t1.id 

JOIN 

(SELECT 
   IF(@cd2 = dt2.code, @rn2 := @rn2 + 1, 1) AS row_num2, 
   @cd2 := dt2.code AS code, 
   dt2.value 
 FROM (SELECT DISTINCT code, value FROM table2 ORDER BY code) AS dt2
 CROSS JOIN (SELECT @rn2 := 1, @cd2 := '') AS init2
) AS t3 
  ON t3.row_num2 = t2.row_num1 AND 
     t3.code = t2.code 

SET t1.value = t3.value 

Upvotes: 1

Madhur Bhaiya
Madhur Bhaiya

Reputation: 28844

This requires Row_Number() Window function's magic! Unfortunately, your MySQL version is 5.7; so a more verbose solution using User-defined variables follows:

UPDATE 
table1 AS t1 

JOIN 

(SELECT 
   dt1.id, 
   IF(@cd1 = dt1.code, @rn1 := @rn1 + 1, 1) AS row_num1, 
   @cd1 := dt1.code AS code 
 FROM (SELECT id, code FROM table1 ORDER BY code, id) AS dt1
 CROSS JOIN (SELECT @rn1 := 0, @cd1 := '') AS init1
) AS t2 
  ON t2.id = t1.id 

JOIN 

(SELECT 
   IF(@cd2 = dt2.code, @rn2 := @rn2 + 1, 1) AS row_num2, 
   @cd2 := dt2.code AS code, 
   dt2.value 
 FROM (SELECT code, value FROM table2 ORDER BY code) AS dt2
 CROSS JOIN (SELECT @rn2 := 0, @cd2 := '') AS init2
) AS t3 
  ON t3.row_num2 = t2.row_num1 AND 
     t3.code = t2.code 

SET t1.value = t3.value 

You can check the explanation of a similar technique in this answer.

Upvotes: 1

Walter Rodriguez
Walter Rodriguez

Reputation: 1

Using OVER functions should work:

Example queries:

select id,code,value,rank() over (partition by code order by id asc) rank_ 
from dbo.table1;

select code,value,dense_rank() over (partition by code order by code,value asc) rank_ from dbo.table2;

Update statment:

UPDATE t 
SET t1.value = t2.value 
FROM (select id,code,value,rank() over (partition by code order by id asc) rank_ from dbo.table1) t1
inner join ( select code,value,dense_rank() over (partition by code order by code,value asc) rank_ from dbo.table2 ) t2
on t1.code = t2.code and t1.rank_ = t2.rank_

Upvotes: 0

Zaynul Abadin Tuhin
Zaynul Abadin Tuhin

Reputation: 31991

use join ,As order does not matter so i think your sample output could be changed

    UPDATE table1 a 
    JOIN table2 b ON a.code= b.code 
    set a.value = b.value 

Upvotes: 0

Related Questions