【问题标题】:How to do a multi word partial search in SQLITE?如何在 SQLITE 中进行多词部分搜索?
【发布时间】:2021-01-20 23:48:20
【问题描述】:

您好,我想在 SQLITE 中编写一个多词部分搜索,例如,如果用户输入“红色”,我将给出名称或颜色或反应性中带有红色的所有抗体,并且如果用户输入“红色 20”我想在名称或颜色或反应性中给出带有红色和 20 的抗体的交集。我已经写了这个,但我认为 SQL 中应该有一些东西可以使它更容易。

const searchMultiWord = (
  index: number,
  amount: number,
  information: string[],
  startDate: number,
  endDate: number,
) => {
  return new Promise<Antibodies[]>((resolve, reject) => {
    let antibodies: Antibodies[] = [];
    let totalCount: number;
    let defaultSql = `SELECT id, name as antibodyName 
                          FROM Antibodies 
                          WHERE id IN (
                            SELECT id FROM
                            (
                              SELECT id FROM Antibodies WHERE name LIKE ?
                              UNION all
                              SELECT antiId FROM AssignedColors WHERE name LIKE ?
                              UNION all
                              SELECT antiId FROM AssignedReactivities WHERE name LIKE ?
                            )`;
    let defaultParams = [`${startDate}`, `${endDate}`, `${amount}`, `${index}`]
    for (let i = 0; i < information.length - 1; i++) {
      defaultSql += `INTERSECT
      SELECT id FROM
      (
        SELECT id FROM Antibodies WHERE name LIKE ?
        UNION all
        SELECT antiId FROM AssignedColors WHERE name LIKE ?
        UNION all
        SELECT antiId FROM AssignedReactivities WHERE name LIKE ?
      )`;
      defaultParams.unshift(`%${information[i]}%`, `%${information[i]}%`, `%${information[i]}%`);
    }
    defaultParams.unshift(`%${information[information.length - 1]}%`, `%${information[information.length - 1]}%`,
      `%${information[information.length - 1]}%`);
    defaultSql += `) AND dateOfCreation >= ? AND dateOfCreation <= ?
    ORDER BY dateOfCreation DESC LIMIT ? OFFSET?;`;
    db.serialize(() => {
      db.each(defaultSql,
        defaultParams
        , (err, antibody) => {
          if (err) {
            return err.message;
          } else {
            db.all('SELECT name, locations, colorId FROM AssignedColors WHERE antiId = ?', [antibody.id], (err, colors) => {
              if (err) {
                reject(err.message)
              } else {
                antibody.colors = colors;
                antibodies.push(antibody);
                if (totalCount === antibodies.length) {
                  resolve(antibodies);
                }
              }
            });
          }
        }, (err, count) => {
          if (err) {
            reject(err.message)
          } else {
            if (count === 0) {
              resolve(antibodies);
            } else {
              totalCount = count;
            }
          }
        });
    });
  });
}

【问题讨论】:

  • 您可以根据提供的单词数(即 WHERE name LIKE )构建您的 WHERE 子句和相应的参数?和名字喜欢?和名字喜欢?等就内置 SQL 支持而言,除了可能使用正则表达式(SQLite 本身不支持)之外,我认为您没有太多选择。

标签: sql typescript sqlite node-sqlite3


【解决方案1】:

为您要搜索的值创建一个CTE,例如'red''20' 以及另一个返回所有3 个表的idname 列的CTE
加入表 group by id 并在 HAVING 子句中设置条件:

WITH 
  search(val) AS (VALUES ('red'), ('20')), 
  cte AS (
    SELECT id, name FROM Antibodies
    UNION ALL
    SELECT antiId, name FROM AssignedColors
    UNION ALL
    SELECT antiId, name FROM AssignedReactivities
  )
SELECT c.id
FROM cte c INNER JOIN search s
ON c.name LIKE '%' || s.val || '%'  
GROUP BY c.id
HAVING COUNT(DISTINCT s.val) = (SELECT COUNT(*) FROM search)

【讨论】:

  • tnx 好友寻求帮助。我找到了这个问题的解决方案stackoverflow.com/questions/64197565/…。但是结果顺序有问题。它有时会搞砸,我不知道为什么。有没有更好的办法?
  • @MjEbrahimzadeh 如果是关于打字稿,那我帮不了你。如果是关于查询,那么如果表中的日期采用以下格式,ORDER BY dateOfCreation DESC 应该会按预期工作:YYYY-MM-DD
  • 不是关于 sqlite 的。当我在每个内部使用 db.each 和 db.all 时,它会破坏我的结果顺序。顺便说一句,tnx 为您提供所有帮助
  • 我实际使用 db.each 的原因是我想从另一个表中获取颜色作为对象数组
  • 然后是打字稿。我不知道foreach 的行为。也许它不保留返回行的顺序。但我不确定。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-11-06
  • 2019-11-10
  • 2019-07-24
  • 1970-01-01
  • 1970-01-01
  • 2020-07-15
  • 1970-01-01
相关资源
最近更新 更多