我有一个带有一个 varchar 列的 sql 表。它包含的一些数据如下:
sadkjlsakjd
Physics Test 2
Test
Test 1
P Test C
Physics Test None
dstestsad
现在,当我使用“Test”关键字搜索时,我需要一个查询,首先给出最相关的记录。我期待着:
Test
Test 1
<Then other records where Test comes in between>
我知道如何使用临时表和交集实现此查询,但对我写的内容一点也不满意。我有一种感觉,应该有一些简单快捷的东西。
请推荐。
谢谢
试试这个:
SELECT colName
FROM tableName
WHERE colName LIKE '%Test%'
ORDER BY CASE WHEN colName LIKE 'Test%' THEN 1 ELSE 2 END, colName
可能是这样的
SELECT * FROM Your_Table WHERE Your_Column LIKE '%Test%'
ORDER BY CASE WHEN Your_Column LIKE 'Test%' THEN 0 ELSE 1 END,Your_Column
我最近正在紧张地研究这个问题,使用 SQL 进行相关性查询。我可能应该写一篇论文或创建一个开源项目,但我工作和家里太忙,所以我会偷懒,我就写在这里。
首先您需要了解相关性计算的准确性取决于您在查询中收集的数据量。因此,您需要权衡性能与准确性。您希望查询的性能越高,您想要读取的数据就越少,但您的结果也会越不准确,因此您需要找到一个平衡点,您的数据会告诉您这一点。
第二您需要将相关性分成单独的标准,并提供一些评分机制,越简单的机制越好,这样就很容易理解,然后您可以从那里进行迭代。听起来很复杂,但其实并不复杂。
UNION ALL
将结果放入单个结果集注意: 查询额外数据非常重要,因此您可以合并分数,因为一个条件可以以一种方式匹配另一个不同的记录。 越高,结果就越准确,因此请确保查询次数超过请求的限制。
例如,如果您希望限制为 10,那么您可能需要查询至少
limit(10) * number_of_criteria_or_more(2)
=> TOP(10 * 2)
在我的例子中,我使用了请求行数的 10 倍,这样我可以获得更好的样本和更多相关结果。
-- starts_with criteria data
WITH StartsWith_Criteria_CTE AS (
SELECT TOP (10 * 2) 2 AS score, test_column FROM test_table WHERE test_column LIKE 'test%'
),
-- contains criteria data
Contains_Criteria_CTE AS (
SELECT TOP (10 * 2) 1 AS score, test_column FROM test_table WHERE test_column LIKE '%test%'
),
-- combine results using union all
CombinedScores_CTE AS (
SELECT score, test_column FROM StartsWith_Criteria_CTE
UNION ALL
SELECT score, test_column FROM Contains_Criteria_CTE
),
-- Aggregate the scores
AggregatedScores_CTE (
SELECT
TOP (10)
SUM(score) AS score,
test_column
FROM CombinedScores_CTE
GROUP BY test_column
ORDER BY score DESC
)
-- get your results
SELECT TOP (10) score, test_column FROM AggregatedScores_CTE;
您将看到 1 代表 contains,3 代表starts_with,因为 contains 和 start_with 重叠。由于这种重叠,有时您需要进行调整以平衡相关性分数。
分数 | 测试列 |
---|---|
3 | 测试1 |
3 | 测试 |
3 | 测试C |
1 | 物理测试2 |
1 | dstestsad |
1 | 物理测试 无 |
这个评分算法很简单,但很有效。 我使用了一个更复杂的分数,该分数基于分数提升因子之上的长度差异,以区分何时存在平局,以保证计算时的正确顺序。
如果您想要更复杂的匹配和决胜计分,那么您可以更新到以下内容。
-- starts_with criteria data
WITH StartsWith_Criteria_CTE AS (
SELECT TOP (10 * 2)
(LEN(test_column)/(LEN(test_column) - LEN('test') + 1.0)) * 2 + 2 AS score,
test_column
FROM test_table WHERE test_column LIKE 'test%'
),
-- contains criteria data
Contains_Criteria_CTE AS (
SELECT TOP (10 * 2)
(LEN(test_column)/(LEN(test_column) - LEN('test') + 1.0)) * 1 + 1 AS score,
test_column FROM test_table
WHERE test_column LIKE '%test%'
),
-- combine results using union all
CombinedScores_CTE AS (
SELECT score, test_column FROM StartsWith_Criteria_CTE
UNION ALL
SELECT score, test_column FROM Contains_Criteria_CTE
),
-- Aggregate the scores
AggregatedScores_CTE (
SELECT
TOP (10)
SUM(score) AS score,
test_column
FROM CombinedScores_CTE
GROUP BY test_column
ORDER BY score DESC
)
-- get your results
SELECT TOP (10) score, test_column FROM AggregatedScores_CTE;
分数 | 测试列 |
---|---|
15.0 | 测试 |
9.0 | 测试1 |
9.0 | 测试C |
2.5 | dstestsad |
2.27 | 物理测试2 |
2.21 | 物理测试 无 |
似乎有点令人困惑,如果您几乎看不出
dstestsad
在那里,为什么 test
会获得更高的分数?但它确实具有最少的字符数。如果我们认为这是一种奇怪的行为,也许我们应该考虑添加一个新的标准来判断输入是否用作单词
-- starts_with criteria data
WITH StartsWith_Criteria_CTE AS (
SELECT TOP (10 * 3)
(LEN(test_column)/(LEN(test_column) - LEN('test') + 1.0)) * 3 + 3 AS score,
test_column
FROM test_table WHERE test_column LIKE 'test%'
),
-- contains criteria data
Contains_Criteria_CTE AS (
SELECT TOP (10 * 3)
(LEN(test_column)/(LEN(test_column) - LEN('test') + 1.0)) * 1 + 1 AS score,
test_column FROM test_table
WHERE test_column LIKE '%test%'
),
-- is a word criteria data
IsAWord_Criteria_CTE AS (
SELECT TOP (10 * 3)
(LEN(test_column)/(LEN(test_column) - LEN('test') + 1.0)) * 2 + 2 AS score,
test_column FROM test_table
WHERE
test_column LIKE 'test %' OR
test_column LIKE '% test %' OR
test_column LIKE '% test' OR
test_column = 'test'
),
-- combine results using union all
CombinedScores_CTE AS (
SELECT score, test_column FROM StartsWith_Criteria_CTE
UNION ALL
SELECT score, test_column FROM Contains_Criteria_CTE
UNION ALL
SELECT score, test_column FROM IsAWord_Criteria_CTE
),
-- Aggregate the scores
AggregatedScores_CTE (
SELECT
TOP (10)
SUM(score) AS score,
test_column
FROM CombinedScores_CTE
GROUP BY test_column
ORDER BY score DESC
)
-- get your results
SELECT score, test_column FROM AggregatedScores_CTE;
现在结果似乎与用户非常相关。
分数 | 测试列 |
---|---|
30.0 | 测试 |
18.0 | 测试1 |
18.0 | 测试C |
6.82 | 物理测试2 |
6.64 | 物理测试 无 |
2.5 | dstestsad |
在您的情况下,您只有 2 个条件,并且
starts_with
和 contains
重叠,如果数据相当小,您可能可以依靠 UNION
的顺序来获取所有数据。
SELECT test_column FROM test_table WHERE test_column LIKE 'test%'
UNION ALL
SELECT test_column FROM test_table WHERE test_column LIKE '%test%' AND NOT test_column LIKE 'test%'