【问题标题】:Search from column with partial matches on values of array on ROOM从与 ROOM 上的数组值部分匹配的列中搜索
【发布时间】:2020-08-20 19:46:49
【问题描述】:

我有一个庞大的邮政编码列表,我需要为其实现搜索功能。
我想做的是:

使用这些字符串中的任何一个,结果 "2695-650, São João da Talha" 应该出现:
《2695》
“2695-650”
“2695 650”
“圣若昂”
"sAo joA da TaLH"
“圣塔哈”
“塔尔乔亚”
“乔奥塔哈”
“塔尔哈 650 乔奥”

我做了一个编辑文本并像这样实现了它的监听器

    txtSearch = root.findViewById(R.id.txtPostalCodeSearch)
    txtSearch?.addTextChangedListener(object : TextWatcher {
        override fun afterTextChanged(s: Editable) { }
        override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) { }
        override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
            var string = s.toString()

            if(string.isNullOrBlank())
                viewModel.getPostalCodes()
            else{
                var filterWord = "%" + string.toLowerCase() + "%"
                viewModel.getFilteredPostalCodes(filterWord)
            }
        }
    })  

而我目前使用的 room dao 查询是:

@Query("SELECT * FROM PostalCode WHERE lower(full_postal_code) LIKE :filterString")
fun SearchQuery(filterString: String) : List<PostalCode?>?  

显然这不会像我想要的那样工作,

我还尝试将搜索字符串拆分为单词并从数组中搜索。

var filterWords = string.toLowerCase().split(" ", "-").toMutableList()
viewModel.getFilteredPostalCodes(filterWords)

并从房间道查询

@Query("SELECT * FROM PostalCode WHERE lower(full_postal_code) IN (:filterStrings)")
fun SearchQueryFromArray(vararg filterStrings: String) : List<PostalCode?>?

但这失败了,因为数组的每个值都不允许部分匹配

最好的方法是什么?

【问题讨论】:

  • 你试过自动完成 TextView 吗?
  • 我应该指定它,但是,我使用这个 textview 来更新它正下方的 recyclerview,自动完成 textview 在这里没有多大帮助。
  • 列表有多大?您可以完全加载它并使用搜索来限制内存中的可见项目
  • 该列表有 367.8k 项并且还在增长。

标签: android sql kotlin android-room


【解决方案1】:

这可能是一个不寻常的想法,但请考虑使用RawQuery。仅当您在定义静态查询文本时遇到问题时才应使用它。但似乎情况可能如此。 主要思想 - 根据您的 filterWords 列表获取动态查询文本(因为您希望列表中的所有单词都与结果匹配):

select * from PostalCode where 
full_postal_code LIKE ? AND full_postal_code LIKE ?  ...

? 在 RawQuery 中用作原始 Sqlite - 作为参数占位符 - 每个搜索词的每个 LIKE 语句)。

所以在你的 Dao 方法中:

@RawQuery
fun getUser(query: SupportSQLiteQuery): List<PostalCode?>?

然后你应该添加辅助方法(也可以放入 dao 中),它应该生成这个带有所需查询字符串的 SupportSQLiteQuery 对象(它不是最佳的,你可以清理它,用 StringBuilder 替换):

fun findUser(filterWords: List<String>): List<PostalCode?>? {
    var queryString = "select * from PostalCode where 1 = 1 " // <- just for easier concat, change it as you like
    repeat(list.size) {searchString += " and user_name LIKE ?"}
    val query = SimpleSQLiteQuery(queryString, filterWords.toTypedArray()) // <- second parameter should be array
    return getUser(query)
}

然后你可以从你的 viewModel/repository 调用这个 findUser 方法。

【讨论】:

    猜你喜欢
    • 2017-05-08
    • 2014-06-21
    • 2014-09-07
    • 2016-01-02
    • 2018-03-24
    • 2015-05-27
    • 2011-10-19
    • 1970-01-01
    • 2012-10-04
    相关资源
    最近更新 更多