简体   繁体   中英

Update rows set uniqe values from another table MySQL

I have two tables for example. First contains generated serials for details. The second contains produced datails. I need to insert unique serial numbers to the second.

T1

t1.ID t1.OBJ_TYPE t1.OBJ_SERIAL
1 5 DRW157001
2 5 DRW157002
3 5 DRW157003
4 5 DRW157004
5 5 DRW157005
6 5 DRW157006

T2

t2.ID t2.DETAIL_TYPE t2.DETAIL_SERIAL
1 5 DRW157001
2 5 DRW157005
3 5 NULL
4 5 NULL
5 5 NULL
6 5 NULL

Is it possible to to make like this after update?

Result

t2.ID t2.DETAIL_TYPE t2.DETAIL_SERIAL
1 5 DRW157001
2 5 DRW157005
3 5 DRW157002
4 5 DRW157003
5 5 DRW157004
6 5 DRW157006

SQL query

UPDATE t2, t1 SET t2.DETAIL_SERIAL = (SELECT t1.OBJ_SERIAL FROM t1 LIMIT 1 ) WHERE t1.OBJ_TYPE = t2.DETAIL_TYPE

Yes, It is possible using JOIN in UPDATE as follows:

UPDATE t2 
 INNER JOIN 
(SELECT T2ID, OBJ_SERIAL 
   FROM (SELECT T1.*, T2.ID T2ID, 
                ROW_NUMBER() OVER (ORDER BY T1.ID) AS T1RN,
                ROW_NUMBER() OVER (ORDER BY T2.ID) AS T2RN
           FROM T1 JOIN T2 ON T1.OBJ_TYPE = T2.DETAIL_TYPE
          WHERE T2.DETAIL_SERIAL IS NULL
            AND NOT EXISTS 
                (SELECT 1 FROM T2 T22 
                  WHERE T1.OBJ_TYPE = T22.DETAIL_TYPE
                    AND T22.DETAIL_SERIAL = T1.OBJ_SERIAL 
                 )
        ) T 
  WHERE T1RN = T2RN) T
 SET T2.DETAIL_SERIAL = T.OBJ_SERIAL 
 WHERE T2.ID = T.T2ID

Now i have that code and it's works for me.

SET @i := 0;
SET @j := 0;

UPDATE t2 DST LEFT JOIN 
(
    SELECT TD1.RNT1, TD1.OBJ_SERIAL, TD2.IDX, TD2.RNT2, TD2.DETAIL_SERIAL FROM 
    (
        SELECT @i := @i + 1 AS RNT1, TSRC1.OBJ_SERIAL FROM t1 TSRC1 WHERE NOT EXISTS ( SELECT 1 FROM t2 TSH1 WHERE TSRC1.OBJ_SERIAL = TSH1.DETAIL_SERIAL AND )
    ) TD1 
    LEFT JOIN 
    (
        SELECT @j := @j + 1 AS RNT2, TSRC2.ID IDX, TSRC2.DETAIL_SERIAL FROM t2 TSRC2 WHERE NOT EXISTS (SELECT 1 FROM t1 TSH2 WHERE TSRC2.DETAIL_SERIAL = TSH2.OBJ_SERIAL) AND TSRC2.DETAIL_SERIAL IS NULL
    ) TD2 
    ON TD1.RNT1 = TD2.RNT2 AND TD1.OBJ_TYPE = TD2.DETAIL_TYPE
) TD3 
ON DST.ID = TD3.IDX 
SET DST.DETAIL_SERIAL = TD3.OBJ_SERIAL
WHERE TD3.IDX IS NOT NULL;

Is there a better way?

This is complicated. The idea is to do the following:

  1. Enumerate the rows in t2 where detail_serial is NULL .
  2. Enumerate the rows in t1 where obj_serial is not being used in t2 .
  3. Join together for the update .

What makes this a bit more complicated, is that (1) requires an additional join (to tt2 in the below query):

update t2 join
       (select t2.*,
               row_number() over (order by t2.id) as seqnum
        from t2
        where t2.DETAIL_SERIAL is null
       ) tt2
       on t2.id = tt2.id join
       (select t1.*,
               row_number() over (order by t1.id) as seqnum
        from t1
        where not exists (select 1
                          from t2
                          where t2.DETAIL_SERIAL = t1.OBJ_SERIAL
                         )
       ) t1
       on t1.seqnum = tt2.seqnum
    set t2.DETAIL_SERIAL = t1.OBJ_SERIAL;

I'm not quite sure where obj_type fits in. However, if it also needs to match, then include it in the not exists subquery and in the final join. Or perhaps you just want to filter on the value.

Here is a db<>fiddle.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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