zoukankan      html  css  js  c++  java
  • Join 实现 2 表数据联动

    最近在做一个简单的报表, 用的工具是帆软报表, 一开始觉得有点low, 现在看看还行, 除了界面真的太丑外, 其它还要, 这种大量要使用 sql 的方式, 我觉得是非常灵活高效的, I like . 这个过程 sql 确实也提高了不少. 其中有个需求, 是要做个数据联动, 报表之间的部分字段的联动变化.

    需求

    两张表, B 表的某些字段要 跟随 A 表的变化实现级联, 也不是级联,就是完全同步.

    分析了一波, 本以为要做个级联操作, 但一看, 其实就是, join 就能解决的呀.

    实现

    首先要考虑 B 表原有的数据不能动, 然后再进行联动.. 还是建表等来说明整个原理吧.

    数据准备

    drop table if exists tb_01;
    create table tb_01(
    	id varchar(20) primary key,
    	name varchar(20),
    	age int,
    	gender varchar(30),
    
    	-- 默认值
    	alive varchar(30) not null default 'alive'
    );
    
    
    insert into tb_01(id, name, age, gender) values ('100', 'youge', 24, '男');
    insert into tb_01(id, name, age, gender) values ('101', 'xiaojie', 22, '女');
    insert into tb_01(id, name, age, gender) values ('102', 'tianer', 22, '女');
    
    
    
    drop table if exists tb_02;
    create table tb_02(
    	id varchar(20) primary key,
    
    	name varchar(20),
    	age int,
    	gender varchar(30),
    
    	dream varchar(20),
    	city varchar(20),
    	income int,
    
    	-- alive 有值表示同步中, 无值则表示离线状态
    	status varchar(20) null
    ); 
    
    
    insert into tb_02(id) values ('100');
    insert into tb_02(id) values ('101');
    insert into tb_02(id) values ('102');
    insert into tb_02(id) values ('103');
    
    

    初始数据如下:

    -- preview
    
    mysql> select * from tb_01;
    +-----+---------+------+--------+
    | id  | name    | age  | gender |
    +-----+---------+------+--------+
    | 100 | youge   |   24 | 男     |
    | 101 | xiaojie |   22 | 女     |
    | 102 | tianer  |   22 | 女     |
    +-----+---------+------+--------+
    3 rows in set (0.00 sec)
    
    mysql> select * from tb_02;
    +-----+------+------+--------+-------+------+--------+-------+
    | id  | name | age  | gender | dream | city | income | alive |
    +-----+------+------+--------+-------+------+--------+-------+
    | 100 | NULL | NULL | NULL   | NULL  | NULL |   NULL | NULL  |
    | 101 | NULL | NULL | NULL   | NULL  | NULL |   NULL | NULL  |
    | 102 | NULL | NULL | NULL   | NULL  | NULL |   NULL | NULL  |
    | 103 | NULL | NULL | NULL   | NULL  | NULL |   NULL | NULL  |
    +-----+------+------+--------+-------+------+--------+-------+
    4 rows in set (0.00 sec)
    

    过程细节

    先要让 B 表的数据不能动, 初始化的时候.

    select
      a.id as a_id,
    
      b.id,
      b.name,
      b.age,
      b.gender,
      b.dream,
      b.city,
      b.income,
      b.alive
    
    from tb_01 as a 
    right join tb_02 as b
      on a.id = b.id
    

    left join 和 right join 灵活使用需要哦

    B 表左连接 A 表 这个结果作为 C 表

    +------+-----+------+------+--------+-------+------+--------+-------+
    | a_id | id  | name | age  | gender | dream | city | income | alive |
    +------+-----+------+------+--------+-------+------+--------+-------+
    | 100  | 100 | NULL | NULL | NULL   | NULL  | NULL |   NULL | NULL  |
    | 101  | 101 | NULL | NULL | NULL   | NULL  | NULL |   NULL | NULL  |
    | 102  | 102 | NULL | NULL | NULL   | NULL  | NULL |   NULL | NULL  |
    | NULL | 103 | NULL | NULL | NULL   | NULL  | NULL |   NULL | NULL  |
    +------+-----+------+------+--------+-------+------+--------+-------+
    

    A 表再 和 C 表做左连接 (同步新增等情况的的数据)

    select 
      a.id,
      a.name,
      a.age,
      a.gender,
    
      -- c.a_id,
      c.dream,
      c.city,
      c.income,
      c.alive
    
    from tb_01 as a
    left join (
    
    	select
    	  a.id as a_id,
    
    	  b.id,
    	  b.name,
    	  b.age,
    	  b.gender,
    	  b.dream,
    	  b.city,
    	  b.income,
    	  b.alive
    
    	from tb_01 as a 
    	right join tb_02 as b
    	  on a.id = b.id 
    
    	) as c
    
      on a.id = c.id
    
    -- A 表删减记录, 不会影响 B 表原有的
     and c.a_id is not null  
    
    
    -- 左边作为作为联动标准(中间表01)
    +-----+---------+------+--------+-------+------+--------+-------+
    | id  | name    | age  | gender | dream | city | income | alive |
    +-----+---------+------+--------+-------+------+--------+-------+
    | 100 | youge   |   24 | 男     | NULL  | NULL |   NULL | NULL  |
    | 101 | xiaojie |   22 | 女     | NULL  | NULL |   NULL | NULL  |
    | 102 | tianer  |   22 | 女     | NULL  | NULL |   NULL | NULL  |
    +-----+---------+------+--------+-------+------+--------+-------+
    3 rows in set (0.00 sec)
    
    

    将此中间表01, 主键插入到 目标表 tb_02

    主键插入: 主键冲突则覆盖, 否则新增,即在帆软的 主键填报

    mysql> select * from tb_02;
    +-----+---------+------+--------+-------+------+--------+-------+
    | id  | name    | age  | gender | dream | city | income | alive |
    +-----+---------+------+--------+-------+------+--------+-------+
    | 100 | youge   |   24 | 男     | NULL  | NULL |   NULL | NULL  |
    | 101 | xiaojie |   22 | 女     | NULL  | NULL |   NULL | NULL  |
    | 102 | tianer  |   22 | 女     | NULL  | NULL |   NULL | NULL  |
    | 103 | NULL    | NULL | NULL   | NULL  | NULL |   NULL | NULL  |
    +-----+---------+------+--------+-------+------+--------+-------+
    4 rows in set (0.00 sec)
    

    等待提交完后, 还要标记出, 哪些是同步的, 哪些是离线的。

    即: 用 A 表 right join 目标表, 能匹配上的, 就是同步的呗。

    -- step_02 (木丁就是 给 alive 字段打上标签)
    
    select 
      b.id,
      b.name,
      b.age,
      b.gender,
      b.dream,
      b.city,
      b.income,
    
      -- 匹配上的 将 alive 填充为 该记录的ID
      a.id as alive
    
    from tb_01 as a 
    right join tb_02 as b 
      on a.id = b.id 
    
    
    +-----+---------+------+--------+-------+------+--------+-------+-------+
    | id  | name    | age  | gender | dream | city | income | alive | alive |
    +-----+---------+------+--------+-------+------+--------+-------+-------+
    | 100 | youge   |   24 | 男     | NULL  | NULL |   NULL | NULL  | 100   |
    | 101 | xiaojie |   22 | 女     | NULL  | NULL |   NULL | NULL  | 101   |
    | 102 | tianer  |   22 | 女     | NULL  | NULL |   NULL | NULL  | 102   |
    | 103 | NULL    | NULL | NULL   | NULL  | NULL |   NULL | NULL  | NULL  |
    +-----+---------+------+--------+-------+------+--------+-------+-------+
    4 rows in set (0.00 sec)
    
    
    => 再  提交一波 (主键插入) 则是最新的了。 
    
    mysql> select * from tb_02;
    +-----+---------+------+--------+-------+------+--------+-------+
    | id  | name    | age  | gender | dream | city | income | alive |
    +-----+---------+------+--------+-------+------+--------+-------+
    | 100 | youge   |   24 | 男     | NULL  | NULL |   NULL | NULL  |
    | 101 | xiaojie |   22 | 女     | NULL  | NULL |   NULL | NULL  |
    | 102 | tianer  |   22 | 女     | NULL  | NULL |   NULL | NULL  |
    | 103 | NULL    | NULL | NULL   | NULL  | NULL |   NULL | NULL  |
    +-----+---------+------+--------+-------+------+--------+-------+
    4 rows in set (0.00 sec)
    
    

    核心过程

    就是两步, 先左连接, 再右连接嘛, 中间需要2次主键插入. 虽然看着这里, sql 很多, 其实主要还是多在字段上, 逻辑非常清晰哦.

    select 
      a.id,
      a.name,
      a.age,
      a.gender,
    
      -- c.a_id,
      c.dream,
      c.city,
      c.income,
      c.alive
    
    from tb_01 as a
    left join (
    
    	select
    	  a.id as a_id,
    
    	  b.id,
    	  b.name,
    	  b.age,
    	  b.gender,
    	  b.dream,
    	  b.city,
    	  b.income,
    	  b.alive
    
    	from tb_01 as a 
    	-- 共有的
    	left join  tb_02 as b
    	  on a.id = b.id 
    
    	) as c
    
      on a.id = c.id
    
     and c.a_id is not null
    
    提交一波哦 !!!
    
    -- step_02 (木丁就是 给 alive 字段打上标签)
    select 
      b.id,
      b.name,
      b.age,
      b.gender,
      b.dream,
      b.city,
      b.income,
    
      -- 匹配上的 将 alive 填充为 该记录的ID
      a.id as alive
    
    from tb_01 as a 
    right join tb_02 as b 
      on a.id = b.id 
    

    简化版(B表跟A表初始一样)

    直接就一个左连接, (主键插入), 然后, 再来一个右连接, 匹配上的 id 给作为 行打上一个标签即可.

    -- step_01:
    select 
      a.*,
      b.dream,
      b.city,
      b.income,
      b.status
    
    from tb_01 as a
    left join tb_02 as b
      on a.id = b.id
    
    -- step_02:
    -- A 表 跟 目标表 右连接, 能匹配上, 就将 
    -- A表的 id 填到 B 的 alive 字段中.
    select 
      b.id,
      b.name,
      b.age,
      b.gender,
      b.dream,
      b.city,
      b.income,
      b.city,
      -- A 表的 id (匹配上)
      a.alive as status
    
    from tb_01 as a
    right join tb_02 as b 
      on a.id = b.id
    

    实现效果

    增改查必然是没有问题的的, 主要来看一波删除操作.

    现在呢, 假设 A 表将 102 给删掉, 那最终的结果呢, 是在 B 表中, status 的状态 alive 变为 空 而已, 达到 逻辑删除 的效果, 这样也更能满足业务的回查数据的需要.

    先一波 102 删除后, 中间表 step_01 的联动效果:

    这时候, 目标表, 一旦 刷新 , 这状态就同步了呀.

    小结

    • 数据联动 Join 左,右 连接, 就能轻松搞定, 一开始想复杂了, 用主外键级联, 和存储过程, 触发器等复杂方式
    • Join 配合这种 "主键更新表" 的方式, 能实现, 标记字段值的回填, 动态插入值, 这种操作还是很强大的
    • SQL 配合相应的工具使用, 如之前的 Tableau 和现用帆软报表, 越来发现 SQL 是真的香.
  • 相关阅读:
    设置开发环境
    安装开发软件
    学习路线
    预备知识
    Spring是什么
    yum安装nginx
    .net 哈希
    Excel文件处理Demo
    汉字处理组件
    Log4Net
  • 原文地址:https://www.cnblogs.com/chenjieyouge/p/12735164.html
Copyright © 2011-2022 走看看