插入数据并用排名填充列

Jac*_*ack 5 mysql sql count sql-update mysql-5.5

原始数据:orginal_table

MID STATE CALL_TIME         RECORD_RANK
a   1    2020-12-18 09:00:00        1
a   2    2020-12-19 09:00:00        2
b   1    2020-12-18 09:00:02        1
c   1    2020-12-18 09:00:03        1
c   1    2020-12-19 09:00:03        2
c   1    2020-12-20 09:00:03        3
d   1    2020-12-19 09:00:00        1
Run Code Online (Sandbox Code Playgroud)

我想插入的数据:insert_table

   MID  STATE      CALL_TIME  
   a    2     2020-12-30 09:00:00      
   b    2     2020-12-19 09:00:02   
   c    1     2020-12-21 09:00:03 
   e    1     2020-12-30 09:00:00 
   f    1     2020-12-30 09:00:00 
   f    2     2020-12-31 09:00:00
Run Code Online (Sandbox Code Playgroud)

目标

  • 原始数据将从第二个数据插入。
  • 对于原始数据和插入数据,该对MID and CALL_TIME是唯一的。
  • RECORD_RANK插入的数据中没有列,但RECORD_RANK会根据MID and CALL_TIME columns插入的时间进行计算。当用不同的 CALL_TIME 复制 MID 时,带有 MID 的 RECORD_RANK 的值将加 1。初始值为 1。
  • insert_table 中最早的行总是晚于 orginal_table 中具有相同 MID 的最新行。

预期的示例结果如下:

MID  STATE      CALL_TIME         RECORD_RANK
a    1    2020-12-18 09:00:00        1
a    2    2020-12-19 09:00:00        2
b    1    2020-12-18 09:00:02        1
c    1    2020-12-18 09:00:03        1
c    1    2020-12-19 09:00:03        2
c    1    2020-12-20 09:00:03        3
d    1    2020-12-19 09:00:00        1
a    2    2020-12-30 09:00:00        3
b    2    2020-12-19 09:00:02        2  
c    1    2020-12-21 09:00:03        4
e    1    2020-12-30 09:00:00        1
f    1    2020-12-30 09:00:00        1 
f    2    2020-12-31 09:00:00        2
Run Code Online (Sandbox Code Playgroud)

笔记

  • mysql 版本:5.5.47-log

GMB*_*GMB 1

insert我认为即使在 MySQL 5.x 中也可以在单个 中处理逻辑。

目标排名是目标表中已存在的同一行的行数mid加上mid源表中当前行之前的行数。您可以使用相关子查询来计算:

insert into orginal_table (mid, state, call_time, record_rank)
select mid, state, call_time,
    1 + (
        select count(*)
        from orginal_table o
        where o.mid = i.mid
    ) + (
        select count(*) 
        from insert_table i1 
        where i1.mid = i.mid and i1.call_time < i.call_time
    ) as record_rank
from insert_table i
Run Code Online (Sandbox Code Playgroud)

正如您的问题中提到的,这假设所有新行都比现有行更新。但如果您想要其他方式,那么可以轻松修复第一个子查询:

(
    select count(*)
    from orginal_table o
    where o.mid = i.mid and o.call_time < i.call_time
)
Run Code Online (Sandbox Code Playgroud)

这是一个基于 Akina 构建的优秀测试用例的演示。

旁注:在 MySQL 8.0 中,我们将使用窗口函数代替第二个子查询,这将使查询更加高效:

insert into orginal_table (mid, state, call_time, record_rank)
select mid, state, call_time,
    row_number() over(partition by mid order by call_time) 
    + (
        select count(*)
        from orginal_table o
        where o.mid = i.mid
    ) as record_rank
from insert_table i
Run Code Online (Sandbox Code Playgroud)