sql - 如何在 SQLITE 中进行多词部分搜索?
问题描述
您好,我想在 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;
}
}
});
});
});
}
解决方案
CTE
为您要搜索的值创建一个,例如'red'
和'20'
另一个CTE
返回所有 3 个表的列id
和name
。
加入表,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)
推荐阅读
- delphi - 列表
其中 T 是一条记录 - javascript - 基于另一个字符串/数组Javascript从1个字符串/数组中删除值
- oracle - 使用 Postgres DDL 创建的表是否会转换为 Liquibase 中的其他 DB DDL?
- c - 如何在C中制作动态结构
- performance-testing - 无法将新计算机添加到 gatling 数据库页面
- python - 将 dictionary_tree 转换为元组列表
- r - 当数据没有按性别分开时,如何单独检查性别分布?
- python - 如何获取与作者相关的点赞总数,并在达到一定数量时使用它发送通知
- arrays - 在 C 中扫描不同数量的数据
- javascript - 在 React 中选择下一个/上一个列表项而不重新渲染