Select 基于多个标签的 SQLite 数据库中的多个数据

Select multiple data from SQLite database based on multiple tags

我有一个带有一些待办事项列表的 SQLite 数据库。 每一个to do list,都有一个tag栏。

这是我的 SQLite 数据库的示例布局

假设我想 select 带有包含“我”和“妈妈”标签的待办事项列表(即“购买杂货”、“学习”和“假期旅行”),我该怎么做这个?

我考虑过这个,但我认为它行不通。

public   getToDoLists (String [] tags) {
    this.db = openHelper.getReadableDatabase();
    String query = " SELECT * FROM "
            + TABLE_NAME
            + " WHERE "
            + COL2 + " ='" + tags + "'";
    c = db.rawQuery(query, null);  
    .......
    .......
 } 

您可以为此使用正则表达式。

注意,默认不提供正则表达式功能,https://sqlite.org/lang_expr.html#regexp:

No regexp() user function is defined by default and so use of the REGEXP operator will normally result in an error message. If an application-defined SQL function named "regexp" is added at run-time, then the "X REGEXP Y" operator will be implemented as a call to "regexp(Y,X)".

您可以使用 ICU 扩展加载正则表达式函数:https://sqlite.org/src/artifact?ci=trunk&filename=ext/icu/README.txt。有了那个:

select
  "To do list"
from table

where 1==1
and (    "Tags" regexp '.*\bMom\b.*'
      or "Tags" regexp '.*\bMe\b.*'  )

ICU 正则表达式语法参考:https://unicode-org.github.io/icu/userguide/strings/regexp.html#regular-expression-metacharacters

这不是一个简单的查询。
您将搜索的标签作为字符串数组传递。
一种选择是使用 for 循环,它将迭代数组的所有标签,并为每个标签 运行 查询,但这对性能不利。

我建议的选项是将所有用 , 分隔的标签连接到一个字符串中,并将其传递给查询,查询又会使用递归 CTE 和 运行 SELECT... 语句和 EXISTS... 来获取匹配的行:

public Cursor getToDoLists(String[] tags) {
    String joinedTags = TextUtils.join(",", tags);

    String query =
            "WITH " +
            "  list(tag) AS (SELECT ?), " +
            "  cte(tag, value) AS ( " +
            "    SELECT SUBSTR(tag, 1, INSTR(tag || ',', ',') - 1), " +
            "           SUBSTR(tag, INSTR(tag || ',', ',') + 1) " +
            "    FROM list " +
            "    UNION ALL " +
            "    SELECT SUBSTR(value, 1, INSTR(value || ',', ',') - 1), " +
            "           SUBSTR(value, INSTR(value || ',', ',') + 1) " +
            "    FROM cte " +
            "    WHERE LENGTH(value) > 0 " +
            ") " +
            "SELECT t.* " +
            "FROM " + TABLE_NAME + " t " +
            "WHERE EXISTS ( " +
            "  SELECT 1 FROM cte c " +
            "  WHERE ',' || REPLACE(t.Tags, ', ', ',') || ',' LIKE '%,' || c.tag || ',%' " +
            ")";

    SQLiteDatabase db = this.getReadableDatabase();

    return db.rawQuery(query, new String[] {joinedTags});
}

我在 sql 语句中使用 REPLACE(t.Tags, ', ', ',') 因为我看到 Tags 列中的标签分隔符是 ', ' 而不是 ',' .
如果我弄错了,请将 REPLACE(t.Tags, ', ', ',') 更改为 t.Tags.

方法 getToDoLists() 必须放在您的 SQLiteOpenHelper class 中,您可以从 activity class 中调用它,例如:

Cursor c = openHelper.getToDoLists(new String[] {"Me", "Mom"});

它 returns 一个 Cursor 的行符合您的条件,您可以对其进行迭代。

要使用 TextUtils.join(),您需要导入:

import android.text.TextUtils;

查看 demo SQLite 中的工作原理。