相关文章推荐
挂过科的雪糕  ·  编译器错误 C2224 | ...·  5 月前    · 
重感情的茶壶  ·  二十、Sql Server ...·  1 年前    · 
买醉的凉面  ·  vue element-ui ...·  1 年前    · 

关于多表查询,之前我写过一篇文章介绍, Android Room 数据库使用@Relation注解进行多表查询-Kotlin ,是基于官方的描述来写的,一直没有机会在项目中使用,但是最近使用的时候才发现了它的问题,当关系表中增加一个标记,就会出现查询的数据不正确的问题;

假设一个音乐类APP,首先有账户系统,也就是有个用户UserInfo的表,然后有歌单GroupInfo的表,歌曲SongInfo的表,有个歌单与歌曲的关系表

* 用户信息 * @Author: D10NG * @Time: 2021/6/3 3:28 下午 @Entity data class UserInfo ( @PrimaryKey var userId : Long = 0 , var name : String = "" ) : Serializable * @Author: D10NG * @Time: 2021/6/3 3:32 下午 @Entity ( primaryKeys = [ "groupId" , "userId" ] data class GroupInfo ( var groupId : Long = 0 , var userId : Long = 0 , var name : String = "" , ) : Serializable * @Author: D10NG * @Time: 2021/6/3 3:35 下午 @Entity ( primaryKeys = [ "songId" , "userId" ] data class SongInfo ( var songId : Long = 0 , var userId : Long = 0 , var name : String = "" ) : Serializable * 歌单与歌的关系 * @Author: D10NG * @Time: 2021/6/3 3:44 下午 @Entity ( primaryKeys = [ "userId" , "groupId" , "songId" ] , foreignKeys = [ ForeignKey ( entity = GroupInfo :: class , parentColumns = [ "groupId" , "userId" ] , childColumns = [ "groupId" , "userId" ] , onDelete = ForeignKey . CASCADE ) ] data class GroupWithSongRelation ( var userId : Long = 0 , var groupId : Long = 0 , var songId : Long = 0 ) : Serializable

然后数据库插入关系数据

// 用户0,歌单0,有歌曲0
db.getGroupWithSongDao().insert(GroupWithSongRelation(0, 0, 0))
// 用户0,歌单1,有歌曲0,1
db.getGroupWithSongDao().insert(GroupWithSongRelation(0, 1, 0))
db.getGroupWithSongDao().insert(GroupWithSongRelation(0, 1, 1))
// 用户0,歌单2,有歌曲0,1,2
db.getGroupWithSongDao().insert(GroupWithSongRelation(0, 2, 0))
db.getGroupWithSongDao().insert(GroupWithSongRelation(0, 2, 1))
db.getGroupWithSongDao().insert(GroupWithSongRelation(0, 2, 2))
// 用户1,歌单0,有歌曲1
db.getGroupWithSongDao().insert(GroupWithSongRelation(1, 0, 1))
// 用户1,歌单1,有歌曲1,2
db.getGroupWithSongDao().insert(GroupWithSongRelation(1, 1, 1))
db.getGroupWithSongDao().insert(GroupWithSongRelation(1, 1, 2))
// 用户1,歌单2,有歌曲1,2,3
db.getGroupWithSongDao().insert(GroupWithSongRelation(1, 2, 1))
db.getGroupWithSongDao().insert(GroupWithSongRelation(1, 2, 2))
db.getGroupWithSongDao().insert(GroupWithSongRelation(1, 2, 3))

编写查询语句

    // 查询歌单带歌曲信息
    @Transaction
    @Query("SELECT * FROM groupinfo WHERE userId = (:userId) AND groupId = (:groupId)")
    suspend fun susQueryGroup(userId: Long, groupId: Long): GroupWithSongData?

查询 用户0 歌单1 的结果为:
在这里插入图片描述
很明显可以看到数据不但重复了,还把属于用户1的歌单给混进来了

直接使用JOIN语句进行查询

    @Query("SELECT * FROM songinfo JOIN (SELECT * FROM groupwithsongrelation WHERE userId = :userId AND groupId = :groupId) groupwithsongrelation ON groupwithsongrelation.songId = SongInfo.songId WHERE SongInfo.userId=:userId")
    suspend fun susQueryGroupSong(userId: Long, groupId: Long): List<SongInfo>
 

JOIN语句中先做一个子查询,把关键数据找出来先
接着,还得在查询结果中增加一个WHERE,将重复数据排除掉

查询结果:
在这里插入图片描述

Github

工程DEMO:
https://github.com/D10NGYANG/RoomDemo

Android-Room数据库(介绍)前言在SQLite数据库中,我们可以指定对象之间的关系,因此我们可以将一个或多个对象与一个或多个其他对象绑定。这就是所谓的一对多和多对多的关系。既然要多表查询,所以表之间就得有关联。这时候我们就得使用新的[emailprotected]接下来的内容,就需要上节的内容了@Entitypublic class Company {@PrimaryKey(autoG... SELECT a.*, dlookup("r1","表2","id=" & a.id & " and name='"& a.name & "'") AS r1, dlookup("r2","表2","id=" & a.id & " and name='"& a.name & "'") AS r2。有两个意义上的重复记录,一是完全重复的记录,也即所有字段均重复的记录,二是部分关键字段重复的记录,比如Name字段重复,而其他字段不一定重复或都重复可以忽略。 Android Room 数据库使用@Relation注解进行多表查询-Kotlin前言参考链接代码创建两个数据表创建记录创建读取合并实体类创建Dao最后 在开发中用到多表一起查询的时候,我以前都是使用这个方法(AndroidRoom数据库多表查询(Relationships))最近发现谷歌原生room里竟然有个@Relation注解用来解决这个问题的,用起来还相当方便,故在此记录一下。 前言在SQLite数据库中,我们可以指定对象之间的关系,因此我们可以将一个或多个对象与一个或多个其他对象绑定。这就是所谓的一对多和多对多的关系。既然要多表查询,所以表之间就得有关联。这时候我们就得使用新的注解符@ForeignKey接下来的内容,就需要上节的内容了@Entitypublic class Company {@PrimaryKey(autoGenerate = true)private... 把json分成省市区三快,三个表(直辖市和省一级,区县和区县一下为一级) 2.建立三个实体对象:ProvinceBean,ShiBean,QuBean 大家会发现没有像网上教程一样使用实体类之间的@ForeignKey外键关联,确实没有(原因是我参考着效果没出来报错),但效果是实现了的,这里实现三个表的联合模糊查询,只在dao层放了一条长长的sql语句: @Entity(tableName = "province") 前言在SQLite数据库中,我们可以指定对象之间的关系,因此我们可以将一个或多个对象与一个或多个其他对象绑定。这就是所谓的一对多和多对多的关系。既然要多表查询,所以表之间就得有关联。这时候我们就得使用新的注解符@ForeignKey接下来的内容,就需要上节的内容了@Entitypublic class Company {@PrimaryKey(autoGenerate = true)private... @Insert(onConflict = OnConflictStrategy.REPLACE) fun insert(singleMessage: SingleMessage) Android 数据库Room的开发使用详解一.简介:Room 在SQLite上提供了一个抽象层,以便在充分利用SQLite的强大功能的同时,能够流畅地访问数据库Room包含3个主要组件:数据库:包含数据库持有者,并作为应用已保留持久性关系型数据的底层连接的主要接入点。@Database注释1.是扩展RoomDatabase的抽象类。2.在注释中添加与数据库关联的实体表。3.包含具有0个参数且返... &nbsp; &nbsp; &nbsp; &nbsp;Room是一个对象关系映射(ORM)库。Room抽象了SQLite的使用,可以在充分利用SQLite的同时访问流畅的数据库。 &nbsp; &nbsp; &nbsp; &nbsp;Room官方文档介绍 https://developer.android.com/training/data-storage/room/ &nbsp; &nbsp... import androidx.room.ColumnInfo; import androidx.room.Entity; import androidx.room.PrimaryKey; @Entity//一张表 public class Student { //主键,自增长 @PrimaryKey(autoGenerate = true) private int id; 可以使用DAO来查询存储数据。这一些列的DAO使用Room的重要组件,每个DAO都提供抽象的数据操作方法 使用DAO操作时,不使用查询构建者或者直接的查询,可以根据自己的数据库结构划分不同的组件。更多的,DAO允许模拟数据库来测试 使用@DAO定义 在添加DAO之前,先将配置添加到build.gradle中 DAO可以是接口或者抽象类。如果是个抽象类,... 多表关联查询1.业务装配方式1.实体类2.mapper 层3.service 层4.测试代码2.单个对象_N+1方式实现1.实体类2.mapper 层3.service 层3.单个对象_关联方式实现1.mapper层4.集合对象_N+1方式实现1.实体类2.mapper 层3.service 层5.集合对象_关联方式实现6.Auto-Mapping配合别名实现 1.业务装配方式 mapper 层只做单表查询操作, 在 service 层进行手动装配, 实现关联查询的结果. 1.实体类 创建班级类(Clazz