精华内容
下载资源
问答
  • HBase建表关联关系,通过hive和其他的组件,关联数据查询,将关系型数据库的数据在分布式集群下的重建。
  • Mybatis的多表关联查询(

    千次阅读 多人点赞 2021-02-12 23:46:03
    Mybatis的多表关联查询()项目目录结构实现 Role 到 User 业务要求用户与角色的关系模型编写角色实体类编写 Role 持久层接口实现的 SQL 语句编写映射文件测试代码实现 User 到 Role 的业务要求...

    mybatis中的多表查询:
    
    	示例:用户和角色
    		一个用户可以有多个角色
    		一个角色可以赋予多个用户
    	步骤:
    		1、建立两张表:用户表,角色表
    			让用户表和角色表具有多对多的关系。需要使用中间表,中间表中包含各自的主键,在中间表中是外键。
    		2、建立两个实体类:用户实体类和角色实体类
    			让用户和角色的实体类能体现出来多对多的关系
    			各自包含对方一个集合引用
    		3、建立两个配置文件
    			用户的配置文件
    			角色的配置文件
    		4、实现配置:
    			当我们查询用户时,可以同时得到用户所包含的角色信息
    			当我们查询角色时,可以同时得到角色的所赋予的用户信息
    

    项目目录结构

    在这里插入图片描述

    实现 Role 到 User 多对多

    多对多关系其实我们看成是双向的一对多关系。

    业务要求

    需求:
    当我们查询角色时,可以同时得到角色的所赋予的用户信息。
    分析:
    查询角色我们需要用到Role表,但角色分配的用户的信息我们并不能直接找到用户信息,而是要通过中间表(USER_ROLE 表)才能关联到用户信息。

    用户与角色的关系模型

    用户与角色的多对多关系模型如下:
    在这里插入图片描述

    角色表:
    在这里插入图片描述
    用户表:
    在这里插入图片描述
    用户角色中间表:
    在这里插入图片描述

    编写角色实体类

    Role:

    package com.keafmd.domain;
    
    import java.io.Serializable;
    import java.util.List;
    
    /**
     * Keafmd
     *
     * @ClassName: Role
     * @Description: 角色实体类
     * @author: 牛哄哄的柯南
     * @date: 2021-02-12 16:45
     */
    public class Role implements Serializable {
    
        private Integer roleId;
        private String roleName;
        private String roleDesc;
    
        //多对多的关系映射
        private List<User> users;
    
        public List<User> getUsers() {
            return users;
        }
    
        public void setUsers(List<User> users) {
            this.users = users;
        }
    
        public Integer getRoleId() {
            return roleId;
        }
    
        public void setRoleId(Integer roleId) {
            this.roleId = roleId;
        }
    
        public String getRoleName() {
            return roleName;
        }
    
        public void setRoleName(String roleName) {
            this.roleName = roleName;
        }
    
        public String getRoleDesc() {
            return roleDesc;
        }
    
        public void setRoleDesc(String roleDesc) {
            this.roleDesc = roleDesc;
        }
    
        @Override
        public String toString() {
            return "Role{" +
                    "roleId=" + roleId +
                    ", roleName='" + roleName + '\'' +
                    ", roleDesc='" + roleDesc + '\'' +
                    '}';
        }
    }
    

    编写 Role 持久层接口

    IRoleDao:

    package com.keafmd.dao;
    import com.keafmd.domain.Role;
    import java.util.List;
    
    /**
     * Keafmd
     *
     * @ClassName: IRoleDao
     * @Description:
     * @author: 牛哄哄的柯南
     * @date: 2021-02-12 19:01
     */
    
    public interface IRoleDao {
    
        /**
         * 查询所有角色
         * @return
         */
        List<Role> findAll();
    
    }
    

    实现的 SQL 语句

    select u.*,r.id as rid ,r.role_name ,r.role_desc from role r  
    left outer join user_role ur on r.id = ur.rid  
    left outer join user u on u.id=ur.uid 
    

    执行结果:
    在这里插入图片描述

    注意:sql语句换行的时候最好在每行的末尾或开头添加空格,这样可以防止合并成一行时发生错误。

    编写映射文件

    IRoleDao.xml:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.keafmd.dao.IRoleDao">
    
        <!--定义role表的resultmap-->
        <resultMap id="roleMap" type="role">
            <id property="roleId" column="rid"></id>
            <result property="roleName" column="role_name"></result>
            <result property="roleDesc" column="role_desc"></result>
            <collection property="users" ofType="user">
                <id column="id" property="id"></id>
                <result column="username" property="username"></result>
                <result column="address" property="address"></result>
                <result column="sex" property="sex"></result>
                <result column="birthday" property="birthday"></result>
            </collection>
        </resultMap>
    
        <!--查询所有-->
        <select id="findAll" resultMap="roleMap">
            select u.*,r.id as rid ,r.role_name ,r.role_desc from role r
            left outer join user_role ur on r.id = ur.rid
            left outer join user u on u.id=ur.uid
        </select>
    
    </mapper>
    

    测试代码

    RoleTest:

    package com.keafmd.test;
    
    import com.keafmd.dao.IRoleDao;
    import com.keafmd.dao.IUserDao;
    import com.keafmd.domain.Role;
    import com.keafmd.domain.User;
    import org.apache.ibatis.io.Resources;
    import org.apache.ibatis.session.SqlSession;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    import org.junit.After;
    import org.junit.Before;
    import org.junit.Test;
    
    import java.io.InputStream;
    import java.util.List;
    
    /**
     * Keafmd
     *
     * @ClassName: MybatisTest
     * @Description: 测试类,测试crud操作
     * @author: 牛哄哄的柯南
     * @date: 2021-02-08 15:24
     */
    public class RoleTest {
    
        private InputStream in;
        private SqlSession sqlsession;
        private IRoleDao roleDao;
    
        @Before // 用于在测试方法执行前执行
        public void init()throws Exception{
            //1.读取配置文件,生成字节输入流
            in = Resources.getResourceAsStream("SqlMapConfig.xml");
            //2.创建SqlSessionFactory工厂
            SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
            SqlSessionFactory factory = builder.build(in);
            //3.使用工厂生产SqlSession对象
            sqlsession = factory.openSession(); //里面写个true,下面每次就不用了写 sqlsession.commit(); 了
            //4.使用SqlSession创建Dao接口的代理对象
            roleDao = sqlsession.getMapper(IRoleDao.class);
        }
    
        @After // 用于在测试方法执行后执行
        public void destory() throws Exception{
            //提交事务
            sqlsession.commit();
            //6.释放资源
            sqlsession.close();
            in.close();
        }
    
    
    
        /**
         * 查询所有
         * @throws Exception
         */
        @Test
        public void testFindAll() {
            List<Role> roles = roleDao.findAll();
            for (Role role : roles) {
                System.out.println("--------每个角色的信息---------");
                System.out.println(role);
                System.out.println(role.getUsers());
               
            }
        }
    
    }
    

    运行结果:

    2021-02-13 00:05:47,481 349    [           main] DEBUG ansaction.jdbc.JdbcTransaction  - Opening JDBC Connection
    2021-02-13 00:05:47,784 652    [           main] DEBUG source.pooled.PooledDataSource  - Created connection 1027007693.
    2021-02-13 00:05:47,784 652    [           main] DEBUG ansaction.jdbc.JdbcTransaction  - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@3d36e4cd]
    2021-02-13 00:05:47,791 659    [           main] DEBUG om.keafmd.dao.IRoleDao.findAll  - ==>  Preparing: select u.*,r.id as rid ,r.role_name ,r.role_desc from role r left outer join user_role ur on r.id = ur.rid left outer join user u on u.id=ur.uid
    2021-02-13 00:05:47,842 710    [           main] DEBUG om.keafmd.dao.IRoleDao.findAll  - ==> Parameters: 
    2021-02-13 00:05:47,869 737    [           main] DEBUG om.keafmd.dao.IRoleDao.findAll  - <==      Total: 4
    --------每个角色的信息---------
    Role{roleId=1, roleName='院长', roleDesc='管理整个学院'}
    [User{id=41, username='老王', sex='男', address='北京', birthday=Tue Feb 27 17:47:08 CST 2018}, User{id=45, username='新一', sex='男', address='北京', birthday=Sun Mar 04 12:04:06 CST 2018}]
    --------每个角色的信息---------
    Role{roleId=2, roleName='总裁', roleDesc='管理整个公司'}
    [User{id=41, username='老王', sex='男', address='北京', birthday=Tue Feb 27 17:47:08 CST 2018}]
    --------每个角色的信息---------
    Role{roleId=3, roleName='校长', roleDesc='管理整个学校'}
    []
    2021-02-13 00:05:47,871 739    [           main] DEBUG ansaction.jdbc.JdbcTransaction  - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@3d36e4cd]
    2021-02-13 00:05:47,872 740    [           main] DEBUG ansaction.jdbc.JdbcTransaction  - Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@3d36e4cd]
    2021-02-13 00:05:47,872 740    [           main] DEBUG source.pooled.PooledDataSource  - Returned connection 1027007693 to pool.
    
    Process finished with exit code 0
    

    实现 User 到 Role 的多对多

    业务要求

    需求:
    当我们查询用户时,可以同时得到用户所包含的角色信息。

    分析:
    相比上面的实现 Role 到 User 多对多,主要变化就是sql语句的变化。

    编写用户实体类

    User:

    package com.keafmd.domain;
    
    import java.io.Serializable;
    import java.util.Date;
    import java.util.List;
    
    /**
     * Keafmd
     *
     * @ClassName: User
     * @Description:
     * @author: 牛哄哄的柯南
     * @date: 2021-02-08 15:16
     */
    
    public class User implements Serializable {
        private Integer id;
        private String username;
        private String sex;
        private String address;
        private Date birthday;
    
        //多对多的关系映射,一个用户可以具备多个角色
        private List<Role> roles;
    
        public List<Role> getRoles() {
            return roles;
        }
    
        public void setRoles(List<Role> roles) {
            this.roles = roles;
        }
    
        public Integer getId() {
            return id;
        }
    
        public void setId(Integer id) {
            this.id = id;
        }
    
        public String getUsername() {
            return username;
        }
    
        public void setUsername(String username) {
            this.username = username;
        }
    
        public String getSex() {
            return sex;
        }
    
        public void setSex(String sex) {
            this.sex = sex;
        }
    
        public String getAddress() {
            return address;
        }
    
        public void setAddress(String address) {
            this.address = address;
        }
    
        public Date getBirthday() {
            return birthday;
        }
    
        public void setBirthday(Date birthday) {
            this.birthday = birthday;
        }
    
        @Override
        public String toString() {
            return "User{" +
                    "id=" + id +
                    ", username='" + username + '\'' +
                    ", sex='" + sex + '\'' +
                    ", address='" + address + '\'' +
                    ", birthday=" + birthday +
                    '}';
        }
    }
    

    编写 User持久层接口

    IUserDao:

    package com.keafmd.dao;
    
    import com.keafmd.domain.User;
    
    import java.util.List;
    
    /**
     * Keafmd
     *
     * @ClassName: IUserDao
     * @Description: 用户的持久层接口
     * @author: 牛哄哄的柯南
     * @date: 2021-02-06 19:29
     */
    
    public interface IUserDao {
        /**
         * 查询所有用户,同时获取到用户下所有账户的信息
         * @return
         */
        List<User> findAll();
    
    }
    

    实现的 SQL 语句

       select u.*,r.id as rid ,r.role_name ,r.role_desc from user u 
       left outer join user_role ur on u.id = ur.uid 
       left outer join role r on r.id=ur.rid 
    

    执行结果:
    在这里插入图片描述

    编写映射文件

    IUserDao.xml:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.keafmd.dao.IUserDao">
    
        <!--定义User的resultMap-->
        <resultMap id="userMap" type="user">
            <id property="id" column="id"></id>
            <result property="username" column="username"></result>
            <result property="address" column="address"></result>
            <result property="sex" column="sex"></result>
            <result property="birthday" column="birthday"></result>
            <!--配置角色集合的映射-->
            <collection property="roles" ofType="role">
                <id property="roleId" column="rid"></id>
                <result property="roleName" column="role_name"></result>
                <result property="roleDesc" column="role_desc"></result>
            </collection>
    
        </resultMap>
    
        <!--配置查询所有-->
        <select id="findAll" resultMap="userMap">
            select u.*,r.id as rid ,r.role_name ,r.role_desc from user u
            left outer join user_role ur on u.id = ur.uid
            left outer join role r on r.id=ur.rid
    
        </select>
    
    </mapper>
    

    测试代码

    UserTest :

    package com.keafmd.test;
    
    import com.keafmd.dao.IUserDao;
    import com.keafmd.domain.User;
    import org.apache.ibatis.io.Resources;
    import org.apache.ibatis.session.SqlSession;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    import org.junit.After;
    import org.junit.Before;
    import org.junit.Test;
    
    import java.io.InputStream;
    import java.util.List;
    
    /**
     * Keafmd
     *
     * @ClassName: MybatisTest
     * @Description: 测试类,测试crud操作
     * @author: 牛哄哄的柯南
     * @date: 2021-02-08 15:24
     */
    public class UserTest {
    
        private InputStream in;
        private SqlSession sqlsession;
        private IUserDao userDao;
    
        @Before // 用于在测试方法执行前执行
        public void init()throws Exception{
            //1.读取配置文件,生成字节输入流
            in = Resources.getResourceAsStream("SqlMapConfig.xml");
            //2.创建SqlSessionFactory工厂
            SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
            SqlSessionFactory factory = builder.build(in);
            //3.使用工厂生产SqlSession对象
            sqlsession = factory.openSession(); //里面写个true,下面每次就不用了写 sqlsession.commit(); 了
            //4.使用SqlSession创建Dao接口的代理对象
            userDao = sqlsession.getMapper(IUserDao.class);
        }
    
        @After // 用于在测试方法执行后执行
        public void destory() throws Exception{
            //提交事务
            sqlsession.commit();
            //6.释放资源
            sqlsession.close();
            in.close();
        }
    
    
    
        /**
         * 查询所有
         * @throws Exception
         */
        @Test
        public void testFindAll() {
            List<User> users = userDao.findAll();
            for (User user : users) {
                System.out.println("--------每个用户的信息---------");
                System.out.println(user);
                System.out.println(user.getRoles());
            }
        }
    
    }
    

    运行结果:

    2021-02-13 00:17:32,971 422    [           main] DEBUG ansaction.jdbc.JdbcTransaction  - Opening JDBC Connection
    2021-02-13 00:17:33,275 726    [           main] DEBUG source.pooled.PooledDataSource  - Created connection 1027007693.
    2021-02-13 00:17:33,275 726    [           main] DEBUG ansaction.jdbc.JdbcTransaction  - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@3d36e4cd]
    2021-02-13 00:17:33,280 731    [           main] DEBUG om.keafmd.dao.IUserDao.findAll  - ==>  Preparing: select u.*,r.id as rid ,r.role_name ,r.role_desc from user u left outer join user_role ur on u.id = ur.uid left outer join role r on r.id=ur.rid
    2021-02-13 00:17:33,319 770    [           main] DEBUG om.keafmd.dao.IUserDao.findAll  - ==> Parameters: 
    2021-02-13 00:17:33,343 794    [           main] DEBUG om.keafmd.dao.IUserDao.findAll  - <==      Total: 10
    --------每个用户的信息---------
    User{id=41, username='老王', sex='男', address='北京', birthday=Tue Feb 27 17:47:08 CST 2018}
    [Role{roleId=1, roleName='院长', roleDesc='管理整个学院'}, Role{roleId=2, roleName='总裁', roleDesc='管理整个公司'}]
    --------每个用户的信息---------
    User{id=42, username='update', sex='男', address='XXXXXXX', birthday=Mon Feb 08 19:37:31 CST 2021}
    []
    --------每个用户的信息---------
    User{id=43, username='小二王', sex='女', address='北京', birthday=Sun Mar 04 11:34:34 CST 2018}
    []
    --------每个用户的信息---------
    User{id=45, username='新一', sex='男', address='北京', birthday=Sun Mar 04 12:04:06 CST 2018}
    [Role{roleId=1, roleName='院长', roleDesc='管理整个学院'}]
    --------每个用户的信息---------
    User{id=50, username='Keafmd', sex='男', address='XXXXXXX', birthday=Mon Feb 08 15:44:01 CST 2021}
    []
    --------每个用户的信息---------
    User{id=51, username='update DAO', sex='男', address='XXXXXXX', birthday=Tue Feb 09 11:31:38 CST 2021}
    []
    --------每个用户的信息---------
    User{id=52, username='Keafmd DAO', sex='男', address='XXXXXXX', birthday=Tue Feb 09 11:29:41 CST 2021}
    []
    --------每个用户的信息---------
    User{id=53, username='Keafmd laset insertid 1', sex='男', address='XXXXXXX', birthday=Fri Feb 12 20:53:46 CST 2021}
    []
    --------每个用户的信息---------
    User{id=54, username='Keafmd laset insertid 2 auto', sex='男', address='XXXXXXX', birthday=Fri Feb 12 21:02:12 CST 2021}
    []
    2021-02-13 00:17:33,345 796    [           main] DEBUG ansaction.jdbc.JdbcTransaction  - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@3d36e4cd]
    2021-02-13 00:17:33,346 797    [           main] DEBUG ansaction.jdbc.JdbcTransaction  - Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@3d36e4cd]
    2021-02-13 00:17:33,346 797    [           main] DEBUG source.pooled.PooledDataSource  - Returned connection 1027007693 to pool.
    
    Process finished with exit code 0
    

    以上就是Mybatis的多表关联查询(多对多)的全部内容。

    看完如果对你有帮助,感谢点赞支持!
    如果你是电脑端的话,看到右下角的 “一键三连” 了吗,没错点它[哈哈]

    在这里插入图片描述

    加油!

    共同努力!

    Keafmd

    展开全文
  • 干货 | Elasticsearch多表关联设计指南

    万次阅读 多人点赞 2019-03-24 23:45:37
    多表关联通常指:1对,或者。 本文以星球问题会出发点,引申出ES多表关联认知,分析了4种关联关系的适用场景、优点、缺点, 希望对你有所启发,为你的多表关联方案选型、实战提供帮助。 1、抛出问题 1.1...

    Elasticsearch 最少必要知识实战教程直播回放

    0、题记

    Elasticsearch多表关联问题是讨论最多的问题之一,如:博客和评论的关系,用户和爱好的关系。
    多表关联通常指:1对多,或者多对多。
    本文以星球问题会出发点,引申出ES多表关联认知,分析了4种关联关系的适用场景、优点、缺点,
    希望对你有所启发,为你的多表关联方案选型、实战提供帮助。

    1、抛出问题

    1.1 星球典型问题

    在这里插入图片描述

    1.2 社区典型问题

    在这里插入图片描述

    1.3 QQ群典型问题

    关系型数据库中的多表之间的关联查询,ES中有什么好的解决方案?
    如果我把关联关系的表迁移到ES中放到一个type下,文档结构除了对象之间的嵌套还有什么好的解决方案?

    2、基础认知

    2.1 关系型数据库

    关系数据库是专门为关系设计的,有如下特点

    • 可以通过主键唯一地标识每个实体(如Mysql中的行)。
    • 实体 规范化 。唯一实体的数据只存储一次,而相关实体只存储它的主键。只能在一个具体位置修改这个实体的数据。
    • 实体可以进行关联查询,可以跨实体搜索。
    • 支持ACID特性,即:单个实体的变化是 原子的 , 一致的 , 隔离的 , 和 持久的 。
    • 大多数关系数据库支持跨多个实体的 ACID 事务。

    关系型数据库的缺陷

    • 第一:全文检索有限的支持能力。 这点,postgresql已部分支持,但相对有限。
    • 第二:多表关联查询的耗时很长,甚至不可用。之前系统开发中使用过Mysql8个表做关联查询,一次查询等待十分钟+,基本不可用。

    2.2 Elasticsearch

    Elasticsearch ,和大多数 NoSQL 数据库类似,是扁平化的。索引是独立文档的集合体。 文档是否匹配搜索请求取决于它是否包含所有的所需信息和关联程度。

    Elasticsearch 中单个文档的数据变更是满足ACID的, 而涉及多个文档时则不支持事务。当一个事务部分失败时,无法回滚索引数据到前一个状态。

    扁平化有以下优势

    1. 索引过程是快速和无锁的。
    2. 搜索过程是快速和无锁的。
    3. 因为每个文档相互都是独立的,大规模数据可以在多个节点上进行分布。

    2.3 Mysql VS Elasticsearch

    • mysql才擅长关系管理,而ES擅长的是检索。

    • Medcl也曾强调:“如果可能,尽量在设计时使用扁平的文档模型。” Elasticsearch的关联存储、检索、聚合操作势必会有非常大的性能开销。
      在这里插入图片描述

    3 Elasticsearch关联关系如何存储

    关联关系仍然非常重要。某些时候,我们需要缩小扁平化和现实世界关系模型的差异。
    以下四种常用的方法,用来在 Elasticsearch 中进行关联数据的管理:

    3.1 应用端关联

    这是普遍使用的技术,即在应用接口层面来处理关联关系。
    针对星球问题实践,

    1. 存储层面:独立两个索引存储。
    2. 实际业务层面分两次请求:

    第一次查询返回:Top5中文姓名和成绩;
    根据第一次查询的结果,第二次查询返回:Top5中文姓名和英文姓名;

    将第一次查询结果和第二次查询结果组合后,返回给用户。
    即:实际业务层面是进行了两次查询,统一返回给用户。用户是无感知的。

    适用场景数据量少的业务场景。
    优点:数据量少时,用户体验好。
    缺点:数据量大,两次查询耗时肯定会比较长,影响用户体验。

    引申场景:关系型数据库和ES 结合,各取所长。将关系型数据库全量同步到 ES 存储,不做冗余存储。
    如前所述:ES 擅长的是检索,而 MySQL 才擅长关系管理。所以可以考虑二者结合,使用 ES 多索引建立相同的别名,针对别名检索到对应 ID 后再回 MySQL 查询,业务层面通过关联 ID join 出需要的数据。

    3.2 宽表冗余存储

    对应于官方文档中的“Data denormalization”,官方直接翻译为:“非规范化你的数据”,总感觉规范化是什么鬼,不好理解。
    通俗解释就是:冗余存储,对每个文档保持一定数量的冗余数据可以在需要访问时避免进行关联。

    这点通过logstash 同步关联数据到ES时,通常会建议:先通过视图对Mysql数据做好多表关联,然后同步视图数据到ES。此处的视图就是宽表。

    针对星球问题实践:姓名、英文名、成绩两张表合为一张表存储。

    适用场景:一对多或者多对多关联。

    优点:速度快。因为每个文档都包含了所需的所有信息,当这些信息需要在查询进行匹配时,并不需要进行昂贵的关联操作。

    缺点:索引更新或删除数据,应用程序不得不处理宽表的冗余数据;
    由于冗余存储,导致某些搜索和聚合操作可能无法按照预期工作。

    3.3 嵌套文档(Nested)存储

    Nested类型是ES Mapping定义的集合类型之一,它是比object类型更NB的支持独立检索的类型。
    举例:有一个文档描述了一个帖子和一个包含帖子上所有评论的内部对象评论。可以借助 Nested 实现。

    实践注意1:当使用嵌套文档时,使用通用的查询方式是无法访问到的,必须使用合适的查询方式(nested query、nested filter、nested facet等),很多场景下,使用嵌套文档的复杂度在于索引阶段对关联关系的组织拼装。

    推荐实践:https://blog.csdn.net/laoyang360/article/details/82950393

    实践注意2

    index.mapping.nested_fields.limit 缺省值是50。即:一个索引中最大允许拥有50个nested类型的数据。
    index.mapping.nested_objects.limit 缺省值是10000。即:1个文档中所有nested类型json对象数据的总量是10000。
    

    适用场景:1 对少量,子文档偶尔更新、查询频繁的场景。
    如果需要索引对象数组并保持数组中每个对象的独立性,则应使用嵌套 Nested 数据类型而不是对象 Oject 数据类型。

    优点:nested文档可以将父子关系的两部分数据(举例:博客+评论)关联起来,可以基于nested类型做任何的查询。
    缺点:查询相对较慢,更新子文档需要更新整篇文档。

    3.4 父子文档存储

    注意:6.X之前的版本的父子文档存储在相同索引的不同type中。而6.X之上的版本,单索引下已不存在多type的概念。父子文档Join的都是基于相同索引相同type实现的。

    Join类型是ES Mapping定义的类型之一,用于在同一索引的文档中创建父/子关系。 关系部分定义文档中的一组可能关系,每个关系是父名称和子名称。

    实践参考:https://blog.csdn.net/laoyang360/article/details/79774481

    适用场景:子文档数据量要明显多于父文档的数据量,存在1 对多量的关系;子文档更新频繁的场景。

    举例:1 个产品和供应商之间是1对N的关联关系。
    当使用父子文档时,使用has_child 或者has_parent做父子关联查询。

    优点:父子文档可独立更新。
    缺点:维护Join关系需要占据部分内存,查询较Nested更耗资源。

    4 小结

    在这里插入图片描述

    1. 在Elasticsearch开发实战中对于多表关联的设计要突破关系型数据库设计的思维定式
    2. 不建议在es做join操作,parent-child能实现部分功能,但是它的开销比较大,如果可能,尽量在设计时使用扁平的文档模型。
    3. 尽量将业务转化为没有关联关系的文档形式,在文档建模处多下功夫,以提升检索效率。
    4. Nested&Join父子文选型必须考虑性能问题。 nested 类型检索使得检索效率慢几倍,父子Join 类型检索会使得检索效率慢几百倍。

    以上内容,实际官方文档都有明确的描述。我把内容加上自己的理解,作了精炼和解读。
    再次强调:第一手资料的重要性。但本着“再显而易见的道理,也有N多人不知道”的原则,一定要读英文官方文档,加深认知理解。

    Elasticsearch多表关联你是如何做的呢?欢迎留言写下您的思考。

    参考:
    [1] https://www.elastic.co/guide/en/elasticsearch/guide/current/relations.html
    [2] rockybean 教程

    在这里插入图片描述
    铭毅天下——Elasticsearch基础、进阶、实战第一公众号

    展开全文
  • Spring Data Mongodb多表关联查询

    万次阅读 2018-12-27 16:19:29
    Spring Data Mongodb使用$lookup实现多表关联查询Spring Data Mongodb多表关联查询前言一、实例1、数据准备2、 一对一:两表关联查询3、一对一:多表关联查询4、一对:关联查询二、讲道理1、自定义...

    Spring Data Mongodb多表关联查询

    前言

    额瑞巴蒂,好。

    最近公司的项目采用Mongodb作为数据库,我也是一头雾水,因为MongoDB是最近几年才火起来,没有什么太多的学习资料。只有看Mongodb官网,Spring Data Mongodb官网文档,看起也比较吃力。所以对Mongodb也是摸着石头过河,有什么不对的地方还请各位老铁多多指教。

    开始吧!

    一、实例

    为了演示对象间一对一、一对多关系,现在创建三张表:公司(Company)、部门(Department)、员工(Employee)

    1、数据准备

    // 公司
    public class Company {
        @Id
        private String id;
    
        private String companyName;
    
        private String mobile;
    }
    
    // 部门
    public class Department {
        @Id
        private String id;
    
        private String departmentName;
    
        @DBRef
        private Company company;
    
        @DBRef
        private List<Employee> employeeList;
    }
    
    // 员工
    public class Employee {
        @Id
        private String id;
        
        private String employeeName;
        
        private String phone;
        
        @DBRef
        private Department department;
    }
    

    创建测试所需的数据:

    	@Autowired
        private MongoTemplate mongoTemplate;
    
        @Test
        public void initData() {
            // 公司
            Company company = new Company();
            company.setCompanyName("XXX公司");
            company.setMobile("023-66668888");
            mongoTemplate.save(company);
    
            // 部门
            Department department = new Department();
            department.setDepartmentName("XXX信息开发系统");
            department.setCompany(company);
            department.setEmployeeList(Collections.emptyList());
            mongoTemplate.save(department);
    
            // 员工
            List<Employee> employeeList = new ArrayList<>();
            Employee employee1 = new Employee();
            employee1.setEmployeeName("张一");
            employee1.setPhone("159228359xx");
            employee1.setDepartment(department);
            employeeList.add(employee1);
    
            Employee employee2 = new Employee();
            employee2.setEmployeeName("张二");
            employee2.setPhone("159228358xx");
            employee2.setDepartment(department);
            employeeList.add(employee2);
            mongoTemplate.insert(employeeList, Employee.class);
    
            department.setEmployeeList(employeeList);
            mongoTemplate.save(department);
        }
    

    2、 一对一:两表关联查询

    RemoveDollarOperation :自定义的Mongodb aggregation管道操作,在稍后的内容中会介绍

       /**
         * 员工表关联部门表
         */
        @Test
        public void twoTableQuery() {
                    // 1、消除@DBRef引用对象中的"$id"的"$"符号
            RemoveDollarOperation removeDollarOperation = new RemoveDollarOperation("newDepartmentFieldName", "department");
    
            // 2、使用mongodb $lookup实现左连接部门表
            LookupOperation lookupOperation = LookupOperation.newLookup().from("department")
                    .localField("newDepartmentFieldName.id").foreignField("_id").as("newDepartment");
    
            // $match条件筛选
    		// MatchOperation matchOperation = new MatchOperation(Criteria.where("newDepartment.departmentName").is("信息开发系统"));
            
            // 3、Aggregation管道操作(还可以加入$match、$project等其他管道操作,但是得注意先后顺序)
            TypedAggregation aggregation = Aggregation.newAggregation(Employee.class, removeDollarOperation, lookupOperation);
    		// TypedAggregation aggregation = Aggregation.newAggregation(Employee.class, removeDollarOperation, lookupOperation, matchOperation);
            AggregationResults<Document> results = mongoTemplate.aggregate(aggregation, Document.class);
    
            System.out.println(JSONArray.toJSONString(results.getMappedResults()));
        }
    

    3、一对一:多表关联查询

    /**
      * 员工表关联部门表,部门表关联公司表
      */
    @Test
    public void threeTableQuery() {
            // 1、消除@DBRef引用对象中的"$id"的"$"符号
            RemoveDollarOperation removeDollarOperation1 = new RemoveDollarOperation("newDepartmentFieldName", "department");
    
            // 2、使用mongodb $lookup实现左连接部门表
            LookupOperation lookupOperation1 = LookupOperation.newLookup().from("department")
                    .localField("newDepartmentFieldName.id").foreignField("_id").as("newDepartment");
    
            // 3、使用$unwind展平步骤二中的左连接的department表的"newDepartment"
            UnwindOperation unwindOperation = new UnwindOperation(Fields.field("$newDepartment"));
    
            // 4、消除@DBRef引用对象中的"$id"的"$"符号
            RemoveDollarOperation removeDollarOperation2 = new RemoveDollarOperation("newCompanyFieldName", "newDepartment.company");
    
            // 5、使用mongodb $lookup实现左连接公司表
            LookupOperation lookupOperation2 = LookupOperation.newLookup().from("company")
                    .localField("newCompanyFieldName.id").foreignField("_id").as("newCompany");
    
            MatchOperation matchOperation = new MatchOperation(Criteria.where("newCompany.companyName").is("XXX公司"));
    
            // 4、Aggregation管道操作(还可以加入$match、$project等其他管道操作,但是得注意先后顺序)
            TypedAggregation aggregation = Aggregation.newAggregation(Employee.class,
                    removeDollarOperation1, lookupOperation1,
                    unwindOperation,
                    removeDollarOperation2, lookupOperation2,
                    matchOperation);
    
            AggregationResults<Document> results = mongoTemplate.aggregate(aggregation, Document.class);
    
            System.out.println(JSONArray.toJSONString(results.getMappedResults()));
    }
    

    4、一对多:关联查询

    	/**
         * 查询部门中的所有员工,部门关联多个员工
         */
        @Test
    	public void oneToManyTableQuery() {
            // 1、展平“多”的一方
            UnwindOperation unwindOperation = new UnwindOperation(Fields.field("employeeList"));
    
            // 2、消除@DBRef引用对象中的"$id"的"$"符号
            RemoveDollarOperation removeDollarOperation1 = new RemoveDollarOperation("newEmployeeFieldName", "employeeList");
    
            // 3、使用mongodb $lookup实现左连接员工表
            LookupOperation lookupOperation1 = LookupOperation.newLookup().from("employee")
                    .localField("newEmployeeFieldName.id").foreignField("_id").as("newEmployee");
    
            // 筛选条件(非必须,看自己是否需要筛选)
            MatchOperation matchOperation = new MatchOperation(Criteria.where("newEmployee.employeeName").is("张一"));
    
            // 4、Aggregation管道操作(还可以加入$match、$project等其他管道操作,但是得注意先后顺序)
            TypedAggregation aggregation = Aggregation.newAggregation(Employee.class,
                    unwindOperation,
                    removeDollarOperation1, lookupOperation1,
                    matchOperation);
    
            AggregationResults<Document> results = mongoTemplate.aggregate(aggregation, Document.class);
    
            System.out.println(JSONArray.toJSONString(results.getMappedResults()));
        }
    

    二、讲道理

    1、自定义RemoveDollarOperation管道操作的作用

    先谈谈mongodb原生$lookup

    我们先来看下mongodb的$lookup操作,这是mongodb $lookup的原生语法

    {
       $lookup:
         {
           from: "collection to join(集合名)",
           localField: "field from the input documents(外键)",
           foreignField: "field from the documents of the "from" collection(被左连接的表的关联主键)",
           as: "output array field(存放连接获得的结果的列名)"
         }
    }
    

    然后使用原生语法进行lookup关联操作,我们来看下员工表与部门表在Mongodb中的数据

    // employee
    {
        "_id": ObjectId("5c244aafc8fbfb40c02d830c"),
        "employeeName": "张一",
        "phone": "159228359xx",
        "department": DBRef("department", ObjectId("5c244aafc8fbfb40c02d830b")),
        "_class": "com.example.mongo.domain.company.Employee"
    }
    
    // department
    {
        "_id": ObjectId("5c244aafc8fbfb40c02d830b"),
        "departmentName": "信息开发系统",
        "company": DBRef("company", ObjectId("5c244aafc8fbfb40c02d830a")),
        "employeeList": [
            DBRef("employee", ObjectId("5c244aafc8fbfb40c02d830c")),
            DBRef("employee", ObjectId("5c244aafc8fbfb40c02d830d"))
        ],
        "_class": "com.example.mongo.domain.company.Department"
    }
    
    

    你以为可以直接通过下面方式进行表连接操作吗,那就错了
    在这里插入图片描述
    执行上面的mongo语句,会报以下错误
    在这里插入图片描述
    错误原因:field的名称不支持以"$"开头

    那问题就来了,既然mongo原生lookup都不支持这一的操作,更何况Spring data mongodb了呢,那"localField"到底该填什么才能实现表关联呢?

    去掉DBRef中"$id"的"$"

    既然不能以"$“开头,那我就把”$"去掉呗:

    MongoDB官方提供的一个方法:https://jira.mongodb.org/browse/SERVER-14466

    db.collection.aggregate({$addFields:{"newFieldName":
         {$arrayToObject:{$map:{
              input:{$objectToArray:"$localFieldName"}, 
              in:{
                 k:{$cond:[ 
                         {$eq:[{"$substrCP":["$$this.k",0,1]},{$literal:"$"}]},
                         {$substrCP:["$$this.k",1,{$strLenCP:"$$this.k"}]},
                         "$$this.k"
                 ]},
                 v:"$$this.v"
               }
             }}}
    }})
    

    使用前:

    "department": DBRef("department", ObjectId("5c244aafc8fbfb40c02d830b"))
    

    使用后:

    "department": {"ref":"department", "id": "5c244aafc8fbfb40c02d830b"}
    

    去除"$“的方式是通过在结果中新追加一列"newFieldName”,这列的值是来至"$localFieldName"。

    所以我们在使用过程中只需替换上面两处的值即可。

    来,我们按这方式操作一波:(修改为"newDepartmentFieldName","$department")

    db.employee.aggregate([{
        "$addFields": {
            "newDepartmentFieldName": {
                "$arrayToObject": {
                    "$map": {
                        "input": {
                            "$objectToArray": "$department"
                        },
                        "in": {
                            "k": {
                                "$cond": [{
                                    "$eq": [{
                                        "$substrCP": ["$$this.k", 0, 1]
                                    }, {
                                        "$literal": "$"
                                    }]
                                }, {
                                    "$substrCP": ["$$this.k", 1, {
                                        "$strLenCP": "$$this.k"
                                    }]
                                }, "$$this.k"]
                            },
                            "v": "$$this.v"
                        }
                    }
                }
            }
        }
    }, {
        "$lookup": {
            "from": "department",
            "localField": "newDepartmentFieldName.id",
            "foreignField": "_id",
            "as": "newDepartment"
        }
    }])
    

    结果出来咯,老铁们

    {
        "_id": ObjectId("5c244aafc8fbfb40c02d830c"),
        "employeeName": "张一",
        "phone": "159228359xx",
        "department": DBRef("department", ObjectId("5c244aafc8fbfb40c02d830b")),
        "_class": "com.example.mongo.domain.company.Employee",
        "newDepartmentFieldName": {
            "ref": "department",
            "id": ObjectId("5c244aafc8fbfb40c02d830b")
        },
        "newDepartment": [
            {
                "_id": ObjectId("5c244aafc8fbfb40c02d830b"),
                "departmentName": "信息开发系统",
                "company": DBRef("company", ObjectId("5c244aafc8fbfb40c02d830a")),
                "employeeList": [
                    DBRef("employee", ObjectId("5c244aafc8fbfb40c02d830c")),
                    DBRef("employee", ObjectId("5c244aafc8fbfb40c02d830d"))
                ],
                "_class": "com.example.mongo.domain.company.Department"
            }
        ]
    }
    
    自定义RemoveDollarOperation管道操作

    前面说了这么多,就是想告诉你们,我为什么要自定义一个RemoveDollarOperation管道操作。就是为了解决Mongodb $lookup的"localField"的值不支持以"$"开头

    以下是RemoveDollarOperation的实现:

    只需implements AggregationOperation,实现toDocument()方法即可

    /**
     * @author : zhangmeng
     * Date : 2018/12/27 11:13
     * Description : 自定义的Spring data mongodb的Aggregation Operation
     */
    public class RemoveDollarOperation implements AggregationOperation {
        /**
         * 查询结果新追加的列名
         */
        private String newField;
    
        /**
         * 需要关联的表中的外键
         */
        private String localField;
    
        public RemoveDollarOperation(String newField, String localField) {
            this.newField = newField;
            this.localField = localField;
        }
    
        @Override
        public Document toDocument(AggregationOperationContext context) {
            List<Object> eqObjects = new ArrayList<>();
            eqObjects.add(new Document("$substrCP", Arrays.asList("$$this.k", 0, 1)));
            eqObjects.add(new Document("$literal", "$"));
    
            List<Object> substrCPObjects = new ArrayList<>();
            substrCPObjects.add("$$this.k");
            substrCPObjects.add(1);
            substrCPObjects.add(new Document("$strLenCP", "$$this.k"));
    
            List<Object> objects = new ArrayList<>();
            objects.add(new Document("$eq", eqObjects));
            objects.add(new Document("$substrCP", substrCPObjects));
            objects.add("$$this.k");
    
            Document operation = new Document(
                    "$addFields",
                    new Document(newField,
                            new Document("$arrayToObject",
                                    new Document("$map",
                                            new Document("input",new Document("$objectToArray", "$"+localField))
                                                    .append("in", new Document("k",new Document("$cond", objects))
                                                            .append("v", "$$this.v")))
                            )
                    )
            );
    
            return context.getMappedObject(operation);
        }
    }
    

    你看到那么多的Document 拼接,其实就是为了实现

    db.collection.aggregate({$addFields:{"newFieldName":
         {$arrayToObject:{$map:{
              input:{$objectToArray:"$localFieldName"},  ...
    

    注意事项:
    在实现过程中,可能因为Spring-data-mongodb版本不同,

    	
    	// Spring-data-mongodb 2.0以上使用Org.bson的Document (具体版本不确定)
    
    	@Override
        public Document toDocument(AggregationOperationContext context) {
        	...
        	...
    		Document operation = new Document(
                    "$addFields",
                    new Document(newField,"")
                    ...
                    ...
            );
    
            return context.getMappedObject(operation);
    	}
    
    	// Spring-data-mongodb 2.0以下使用com.mongodb.BasicDBObject
    	
    	@Override
        public DBObject toDBObject(AggregationOperationContext context) {
    		...
        	...
    		DBObject operation = new DBObject (
                    "$addFields",
                    new DBObject (newField,"")
                    ...
                    ...
            );
    
            return context.getMappedObject(operation);
    }
    

    2、实例中的一对一多表关联查询中的第4步使用UnwindOperation的原因

    可能当我们实现了实例1中的一对一两表关联查询后,顺理成章就觉得如果要再关联第三张表的话,直接再使用

    一次RemoveDollarOperation,LookupOperation进行关联

    db.employee.aggregate([{
        "$addFields": {
            "newDepartmentFieldName": {
                "$arrayToObject": {
                    "$map": {
                        "input": {
                            "$objectToArray": "$department"
                        },
                        "in": {
                            "k": {
                                "$cond": [{
                                    "$eq": [{
                                        "$substrCP": ["$$this.k", 0, 1]
                                    }, {
                                        "$literal": "$"
                                    }]
                                }, {
                                    "$substrCP": ["$$this.k", 1, {
                                        "$strLenCP": "$$this.k"
                                    }]
                                }, "$$this.k"]
                            },
                            "v": "$$this.v"
                        }
                    }
                }
            }
        }
    }, {
        "$lookup": {
            "from": "department",
            "localField": "newDepartmentFieldName.id",
            "foreignField": "_id",
            "as": "newDepartment"
        }
    }, {
        "$addFields": {
            "newCompanyFieldName": {
                "$arrayToObject": {
                    "$map": {
                        "input": {
                            "$objectToArray": "$newDepartment.company"
                        },
                        "in": {
                            "k": {
                                "$cond": [{
                                    "$eq": [{
                                        "$substrCP": ["$$this.k", 0, 1]
                                    }, {
                                        "$literal": "$"
                                    }]
                                }, {
                                    "$substrCP": ["$$this.k", 1, {
                                        "$strLenCP": "$$this.k"
                                    }]
                                }, "$$this.k"]
                            },
                            "v": "$$this.v"
                        }
                    }
                }
            }
        }
    }, {
        "$lookup": {
            "from": "company",
            "localField": "newCompanyFieldName.id",
            "foreignField": "_id",
            "as": "newCompany"
        }
    }])
    

    但是,执行后就错了:
    在这里插入图片描述

    来来来,我们一步一步分析下

    这是Employee关联Department后,得到的结果,“newDepartment"是关联后得到的结果:
    在这里插入图片描述
    我们如果要进一步Department关联Company的话,直接再使用RemoveDollarOperation,LookupOperation是不行的,因为在消除”$"操作时入参需要一个非数组对象,而前一步的结果的"newDepartment"是一个数组,所以报错了
    在这里插入图片描述

    为了得到一个非数组对象,我们就要使用$unwind将"newDepartment"展平
    在这里插入图片描述

    然后就可以使用"newDepartment"继续RemoveDollarOperation,LookupOperation操作了。最终得到Employee关

    联Department关联Company的结果了。如果还想继续关联,就以此类推。

    最终得出的模型:
    
    一对一两表关联的步骤:
    1、RemoveDollarOperation
    2、LookupOperation
    
    一对一多表关联的步骤:
    1、RemoveDollarOperation  2、LookupOperation
    3、UnwindOperation
    4、RemoveDollarOperation  5、LookupOperation
    ...
    
    一对多表关联的步骤:
    1、UnwindOperation
    2、RemoveDollarOperation
    3、LookupOperation
    
    展开全文
  • Eggjs Sequelize 多表关联查询

    千次阅读 2020-07-03 16:35:50
    写服务端的新手,我们项目用nodejs写...实现:通过 fdc_vd_user_his 表关联外键,查询 fdc_vd_user_page 表及 fdc_pro_user_project 表 数据模型: fdc_vd_user_page fdc_pro_user_project fdc_vd_user_his

    写服务端的新手,我们项目用nodejs写服务端,框架是egg.js。对于简单的 增、删、改、查 新手的我也是快速上手了,但是当我遇到需要关联其他表查询时,我就懵逼了,不知道怎么关联啊。几经周折,总算搞明白了,特此记录一下~~~

    实现:通过 fdc_vd_user_his 表关联外键,查询 fdc_vd_user_page 表及 fdc_pro_user_project 表

    数据模型:

    fdc_vd_user_page

    fdc_pro_user_project

    fdc_vd_user_his

    'use strict';
    
    // 个人操作历史表
    module.exports = app => {
      const { STRING, INTEGER, DATE, TEXT } = app.Sequelize;
      const FdcVdUserHis = app.model.define('fdc_vd_user_his', {
        id: {
          type: INTEGER(11),
          primaryKey: true,
          autoIncrement: true,
        },
        page_name: STRING(20), // 页面名称
        page_id: INTEGER(11), // 页面id
        pro_id: INTEGER(11), // 项目id
        create_user: STRING(64), // 创建用户
        create_time: DATE, // 创建时间
        page_json: TEXT, // 页面内容
      });
    
       /* 
         关联表
         foreignKey:当前表通过哪个键关联另一张表
         targetKey:当前表的foreignKey关联另一张表的哪个键,
         如果targetKey是表的主键,可以省略
         as: 别名
      */
      FdcVdUserHis.associate = function() {
        app.model.FdcVd.FdcVdUserHis.belongsTo(app.model.FdcVd.FdcVdUserPage, {
          foreignKey: 'page_id',
          targetKey: 'id',
          as: 'userPage',
        });
    
        app.model.FdcVd.FdcVdUserHis.belongsTo(app.model.FdcProUserProject, {
          foreignKey: 'pro_id',
          as: 'project', //
        });
      };
    
      return FdcVdUserHis;

    关联查询:

    //这里的 as需要与之前定义的as名字相同

    查询方式一:

    查询结果:

    查询方式二: 

    查询结果:

    查询方式三:

    查询结果:

    查询条件,注:如果给include 表加where条件 须使用 '$project.pro_en_name$' 这种写法;也可在include加where条件

    例如:下面的searchCondition就是传入到上面查询where的条件

    展开全文
  • PostgreSQL 多表关联删除

    千次阅读 2020-09-06 15:21:44
    用PostgreSQL数据库删除某个数据 student,需要关联多(如classroom)作为条件,以下语句走不通: delete s.* from student s,classroom c where s.cid = c.id and s.sid = 1 delete from student s,...
  • Springboot整合JPA 多表关联操作 @Query

    千次阅读 2019-10-14 13:10:05
    这篇文章里我所采取的是使用Map来 替代 关联的接口,网上很都是为了关联A B两个,选择新建A&B这个interface去实现关联获取查询出来的数据。还有就是涉及主外键那种,需要在实体类上面使用@ManyToOne/@Many.....
  • 在开发的过程中,由于持久层使用的是非关系型数据库mongodb,涉及到列表查询的多表关联查询,在实现此功能的过程中出现了不少问题,做下记录方便以后遇到此类问题可以快速的解决,同时为遇到此类问题的小伙伴提供...
  • Oracle:多表关联更新字段(update)

    万次阅读 2019-11-13 09:21:25
    Oracle可以用以下两种方式实现多表关联更新字段: update ( select t1.name name1, t2.name name2 from table1 t1 left join table2 t2 on t1.id = t2.id where t1.age > 20 ) tmp set tmp.name1 = tmp.name2...
  • MySQL多表关联查询优化

    千次阅读 2019-11-28 10:37:20
    最近在对运营报表导出进行优化,总结了一些多表关联查询优化的点记录一下。 避免临时表 通过 Explain 分析 SQL 语句,尽量不要使用到临时表。GROUP BY (Explain具体详解,可以看这篇博客) 最容易造成使用临时表,...
  • 多表关联查询之内关联,左关联

    千次阅读 2019-08-22 17:55:24
    -- 同学持有的手机记录 create table student_phone ( id int primary key, stu_name varchar2(20), phone varchar2(200) ) insert into student_phone values (1,'小红','华为 荣耀v9'); insert into student_...
  • DB2多表关联UPDATE 语句

    千次阅读 2019-08-01 10:20:30
    血的教训换来的,最后一定...否则,会将没有关联上的数据字段更新成null. update TM_INS_PROPOSAL TIP set (Total_Amount, Receivable_Busi_Amount, Vehicle_Relation, Busi_Ins_Code, Com_Ins_Code )=(sele...
  • SQL语句多表关联查询语法

    千次阅读 2021-03-03 10:11:37
    **sql语句多表关联查询语法** 一、外连接 1.左连接 left join 或 left outer join SQL语句:select * from student left join score on student.Num=score.Stu_id; 2.右连接 right join 或 right outer join SQL...
  • oracle update 多表关联更新

    千次阅读 2020-07-08 09:04:05
    oracle 多表关联更新 update t_water_livestock_breed_2020 t set t.type_identified = (select r.iteam_code from t_dict_dictionary_iteam r where t.type_identified = r.iteam_name and r.class...
  • SQL-多表关联查询详解

    千次阅读 2019-12-19 23:26:59
    为了在工作中能更顺利的使用多表关联查询,今天这篇博客就写这个内容了。 在讲解多表关联查询之前,先生成测试表。 登录scott用户,运行以下语句生成测试表。 create table ex1 as select * from emp; create table ...
  • 一对多关联查询: db.mall_goods.aggregate([ { $lookup: { from: "mall_specs", localField: "id", foreignField: "goods_id", as: "inventory_docs" } } ]);...
  • mysql 多表关联操作

    千次阅读 2018-07-05 11:39:05
    两张表关联删除:DELETE a,b FROM table1 a INNER JOIN table2 b ON a.id = b.aid WHERE a.id = '1' //或者也可以 DELETE a,b FROM table1 a,table2 b WHERE a.id = b.aid AND a.id = '1'三张表删除DELETE a,b,c ...
  • MySQL 多表关联一对查询取最新的一条数据

    万次阅读 多人点赞 2019-01-23 18:10:27
    MySQL 多表关联一对查询取最新的一条数据 遇到的问题 多表关联一对查询取最新的一条数据,数据出现重复 由于历史原因,表结构设计不合理;产品告诉我说需要导出客户信息数据,需要导出客户的 所属行业,纳税...
  • postgresql 多表关联删除

    万次阅读 2019-01-24 17:44:29
    表关联,删除一张表中数据 delete from db_lx.t_aj_ajfbxx ajfb USING db_lx.t_xt_dwxx dw where dw.c_bh=ajfb.c_ssdw and dw.c_sfbh='65'; 只有t_aj_ajfbxx 表中数据被删除 三表关联,删除一张表中数据 dele.....
  • SQL语言多表关联查询

    千次阅读 2020-05-25 22:59:45
    新建两张1:student 截图如下: 2:course 截图如下: (此时这样建表只是为了演示连接SQL语句,当然实际开发中我们不会这样建表,实际开发中这两个会有自己不同的主键。) 一、外连接 外连接可...
  • oracle多表关联更新

    千次阅读 2019-06-25 14:02:25
    oracle的更新语句不通MSSQL那么简单易写,就算写出来了,但执行时可能会报 这是由于set哪里... 快速游标更新法 多表关联且逻辑复杂的,采用此方案更优。 转自: https://www.cnblogs.com/jingbf-BI/p/4909612.html
  • update语句多表关联

    万次阅读 2018-03-06 20:26:42
    update table1 a set a.ziduan = (select b.newziduan from table2 b where a.id = b.id)
  • jpa多表关联条件查询实现

    千次阅读 2020-12-23 14:32:59
    jpa对于多表关联可以在实体类中进行关联映射,一对一用@OneToOne,一对多用@OneToMany,对多用@ManyToMany,对一用@ManyToOne,具体实体类配置就不说了,然后对于条件查询采用Specification对象进行封装,如下...
  • mysql多表关联删除

    千次阅读 2019-07-09 23:52:07
    现有三张表table_a、table_b、table_c ,三张表的关联关系为:table_aname字段关联table_bname字段,table_a的number字段关联table_c的number字段。SQL命令如下: DELETE table_a, table_b, table_c ...
  • SQL多表关联查询

    千次阅读 2019-09-19 09:26:01
    有时候,我们查询数据时,会采用数据库关联查询的方式。数据库通过连接两张张表查询时,会生成一张临时的中间,然后返回给用户的就是这张临时的数据。那么具体怎么操作呢?我们可以采用left join,搭配...
  • Oracle update 多表关联更新

    千次阅读 2020-05-21 17:05:56
    需求 有一个部门的(dept), 部门编号(deptno) 部门员工数(emps) 部门员工的总工资(income) ...update 1 set 列名=(select 列名 from 2 where 1.列名=2.列名) where exists (select 1 from 2
  • 在企业系统中经常会使用到给用户分配权限的情况,往往在用户信息和...那么,查询用户权限的多表查询sql语句长什么样呢? select * from pe_role_user ru inner join pe_role_module rm on ru.role_id=rm.`role_id...
  • 多表关联如何建立索引

    千次阅读 2019-10-22 11:23:16
    我是用的三张表进行关联的,一大两小。下面看一下三张表的具体结构。 三张图对应三张表,然后下面是我写的查询sql select a.*, b.*, c.* from statjiankong_etl a left join ibnr b on a.anadate = b....
  • Mybatis-plus带查询参数的多表关联

    千次阅读 2020-05-08 08:34:03
    Mybatis-Plus缺省是不带多表关联功能,多表关联需要作用mapper.xml写SQL语句,或都在domain的mapper对象下使用@select注解写SQL语句,用后种方法根据自己的需要,花了一天时间学习研究,做了自己的第一个带查询条件...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 868,513
精华内容 347,405
关键字:

多表关联