Android 房间:针对字符串列查询列表项
Android room: query list items against string column
我有一个字符串列表:
val mylist = listOf("cat","flower")
和一个 table,它有一个名为 question
的字符串类型的列
我可以编写查询来查找与列表项之一完全匹配的问题:
@Query("SELECT * FROM objects WHERE question IN (:mylist)")
List<Object> queryObjects(List<String> mylist);
但实际上问题列数据不是单词类型,而是字符串。我需要找到每个列表项都在该字符串中的结果。例如记录:is this a cat
IN 的使用基本上是对 IN 子句左侧的表达式与右侧值列表的 = 测试。那只是考虑完全匹配。
然而,你想要的是多个带有通配符的 LIKE,并且每个 LIKE 之间有一个 OR 例如 question LIKE '%cat%' OR question LIKE '%flower%'
或 CASE WHEN THEN ELSE END
或者递归通用 table 表达式 (CTE)。
前两个(LIKE 或 CASE)可能必须通过 @RawQuery
完成,其中 LIKE/CASE 子句是在 运行 时构建的。
递归 CTE 选项基本上会构建一个单词列表(但如果包含标点符号等除空格以外的任何内容,可能会变得更加复杂。)
另一种选择是考虑全文搜索 (FTS)。不妨参考https://www.raywenderlich.com/14292824-full-text-search-in-room-tutorial-getting-started
工作示例 赞
下面是一个最简单的例子,多个 LIKE 子句用 OR 分隔:-
对象(实体):-
@Entity
data class Objects(
@PrimaryKey
val id: Long? = null,
val question: String
)
AllDAO(道):-
@Dao
interface AllDAO {
@Insert(onConflict = OnConflictStrategy.IGNORE)
fun insert(objects: Objects)
@RawQuery
fun getObjectsRawQuery(query: SupportSQLiteQuery): List<Objects>
fun getObjects(values: List<String>): List<Objects> {
var i = 0
val sb = StringBuilder().append("SELECT * FROM objects WHERE ")
for(v in values) {
if (i++ > 0) {
sb.append(" OR ")
}
sb.append(" question LIKE '%${v}%'")
}
sb.append(";")
return getObjectsRawQuery(SimpleSQLiteQuery(sb.toString()))
}
}
TheDatabase(为方便起见,未使用 .allowMainThreadQueries
):-
@Database(entities = [Objects::class], version = 1, exportSchema = false)
abstract class TheDatabase: RoomDatabase() {
abstract fun getAllDAO(): AllDAO
companion object {
var instance: TheDatabase? = null
fun getInstance(context: Context): TheDatabase {
if (instance == null) {
instance = Room.databaseBuilder(context,TheDatabase::class.java,"the_database.db")
.allowMainThreadQueries()
.build()
}
return instance as TheDatabase
}
}
}
将它们放在一起,加载一些测试数据并运行提取一些数据:-
class MainActivity : AppCompatActivity() {
lateinit var db: TheDatabase
lateinit var dao: AllDAO
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
db = TheDatabase.getInstance(this)
dao = db.getAllDAO()
dao.insert(Objects(question = "This is a cat."))
dao.insert(Objects(question = "This is a flower."))
dao.insert(Objects(question = "this is nothing."))
dao.insert(Objects(question = "The quick brown fox jumped over the lazy dog"))
logObjects(dao.getObjects(listOf("cat","dog")),"Extract1\t")
logObjects(dao.getObjects(listOf("flower","cat")),"Extract2\t")
logObjects(dao.getObjects(listOf("brown","nothing")),"Extract3\t")
}
fun logObjects(objects: List<Objects>,prefix: String) {
for (o in objects) {
Log.d("OBJECTINFO","$prefix Question is ${o.question} ID is ${o.id}")
}
}
}
结果
2022-04-18 04:58:05.471 D/OBJECTINFO: Extract1 Question is This is a cat. ID is 1
2022-04-18 04:58:05.471 D/OBJECTINFO: Extract1 Question is The quick brown fox jumped over the lazy dog ID is 4
2022-04-18 04:58:05.473 D/OBJECTINFO: Extract2 Question is This is a cat. ID is 1
2022-04-18 04:58:05.473 D/OBJECTINFO: Extract2 Question is This is a flower. ID is 2
2022-04-18 04:58:05.474 D/OBJECTINFO: Extract3 Question is this is nothing. ID is 3
2022-04-18 04:58:05.474 D/OBJECTINFO: Extract3 Question is The quick brown fox jumped over the lazy dog ID is 4
- 注意上面没有考虑处理空列表(由于
SELECT * FROM objects WHERE ;
的语法错误会导致失败)。也就是说这个例子只是为了演示基本原理。
我有一个字符串列表:
val mylist = listOf("cat","flower")
和一个 table,它有一个名为 question
的字符串类型的列
我可以编写查询来查找与列表项之一完全匹配的问题:
@Query("SELECT * FROM objects WHERE question IN (:mylist)")
List<Object> queryObjects(List<String> mylist);
但实际上问题列数据不是单词类型,而是字符串。我需要找到每个列表项都在该字符串中的结果。例如记录:is this a cat
IN 的使用基本上是对 IN 子句左侧的表达式与右侧值列表的 = 测试。那只是考虑完全匹配。
然而,你想要的是多个带有通配符的 LIKE,并且每个 LIKE 之间有一个 OR 例如 question LIKE '%cat%' OR question LIKE '%flower%'
或 CASE WHEN THEN ELSE END
或者递归通用 table 表达式 (CTE)。
前两个(LIKE 或 CASE)可能必须通过 @RawQuery
完成,其中 LIKE/CASE 子句是在 运行 时构建的。
递归 CTE 选项基本上会构建一个单词列表(但如果包含标点符号等除空格以外的任何内容,可能会变得更加复杂。)
另一种选择是考虑全文搜索 (FTS)。不妨参考https://www.raywenderlich.com/14292824-full-text-search-in-room-tutorial-getting-started
工作示例 赞
下面是一个最简单的例子,多个 LIKE 子句用 OR 分隔:-
对象(实体):-
@Entity
data class Objects(
@PrimaryKey
val id: Long? = null,
val question: String
)
AllDAO(道):-
@Dao
interface AllDAO {
@Insert(onConflict = OnConflictStrategy.IGNORE)
fun insert(objects: Objects)
@RawQuery
fun getObjectsRawQuery(query: SupportSQLiteQuery): List<Objects>
fun getObjects(values: List<String>): List<Objects> {
var i = 0
val sb = StringBuilder().append("SELECT * FROM objects WHERE ")
for(v in values) {
if (i++ > 0) {
sb.append(" OR ")
}
sb.append(" question LIKE '%${v}%'")
}
sb.append(";")
return getObjectsRawQuery(SimpleSQLiteQuery(sb.toString()))
}
}
TheDatabase(为方便起见,未使用 .allowMainThreadQueries
):-
@Database(entities = [Objects::class], version = 1, exportSchema = false)
abstract class TheDatabase: RoomDatabase() {
abstract fun getAllDAO(): AllDAO
companion object {
var instance: TheDatabase? = null
fun getInstance(context: Context): TheDatabase {
if (instance == null) {
instance = Room.databaseBuilder(context,TheDatabase::class.java,"the_database.db")
.allowMainThreadQueries()
.build()
}
return instance as TheDatabase
}
}
}
将它们放在一起,加载一些测试数据并运行提取一些数据:-
class MainActivity : AppCompatActivity() {
lateinit var db: TheDatabase
lateinit var dao: AllDAO
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
db = TheDatabase.getInstance(this)
dao = db.getAllDAO()
dao.insert(Objects(question = "This is a cat."))
dao.insert(Objects(question = "This is a flower."))
dao.insert(Objects(question = "this is nothing."))
dao.insert(Objects(question = "The quick brown fox jumped over the lazy dog"))
logObjects(dao.getObjects(listOf("cat","dog")),"Extract1\t")
logObjects(dao.getObjects(listOf("flower","cat")),"Extract2\t")
logObjects(dao.getObjects(listOf("brown","nothing")),"Extract3\t")
}
fun logObjects(objects: List<Objects>,prefix: String) {
for (o in objects) {
Log.d("OBJECTINFO","$prefix Question is ${o.question} ID is ${o.id}")
}
}
}
结果
2022-04-18 04:58:05.471 D/OBJECTINFO: Extract1 Question is This is a cat. ID is 1
2022-04-18 04:58:05.471 D/OBJECTINFO: Extract1 Question is The quick brown fox jumped over the lazy dog ID is 4
2022-04-18 04:58:05.473 D/OBJECTINFO: Extract2 Question is This is a cat. ID is 1
2022-04-18 04:58:05.473 D/OBJECTINFO: Extract2 Question is This is a flower. ID is 2
2022-04-18 04:58:05.474 D/OBJECTINFO: Extract3 Question is this is nothing. ID is 3
2022-04-18 04:58:05.474 D/OBJECTINFO: Extract3 Question is The quick brown fox jumped over the lazy dog ID is 4
- 注意上面没有考虑处理空列表(由于
SELECT * FROM objects WHERE ;
的语法错误会导致失败)。也就是说这个例子只是为了演示基本原理。