2

我有一个查询:

SELECT *
FROM Items
WHERE column LIKE '%foo%'
   OR column LIKE '%bar%'

我如何订购结果?

假设我有与“foo”匹配的行和与“bar”匹配的行,但我也有与“foobar”匹配的行。

如何对返回的行进行排序,以便第一个结果是匹配更多 LIKE 的结果?

4

10 回答 10

4

案例或 RDBMS 支持的条件构造是一种方法

select *, case when col like '%foo%' and col like '%bar%' then 2 end 
else 1 end as ordcol 
from items 
where col like '%foo%' or col like '%bar%' order by ordcol
于 2008-09-17T02:43:43.147 回答
2
SELECT * FROM Items WHERE column LIKE '%foo%' OR column LIKE '%bar%' 
ORDER BY 
(IF(column LIKE '%foo%',1,0) + IF(column LIKE '%bar%',1,0)) 
DESC

if 的语法是

IF ( condition, true_value, false_value )

于 2008-09-17T02:48:10.577 回答
1
SELECT * FROM Items
WHERE col LIKE '%foo%'
    OR col LIKE '%bar%'
ORDER BY CASE WHEN col LIKE '%foo%' THEN 1
                WHEN col LIKE '%bar%' THEN 2
            END
于 2008-09-17T10:21:25.883 回答
1

您可以使用UNION

SELECT * FROM Items WHERE column LIKE '%foo%' AND column LIKE '%bar%'
UNION
SELECT * FROM Items WHERE column LIKE '%foo%' AND NOT (column LIKE '%bar%')
UNION
SELECT * FROM Items WHERE column LIKE '%bar%' AND NOT (column LIKE '%foo%');

但这在性能方面可能很糟糕。更糟糕的是,我猜你想用它来构建一个搜索引擎,首先给出最有意义的结果,然后单词的数量不限制为 2。

在这种情况下,您可以创建一个score包含匹配数的列。像这样的东西:

SELECT
    *,
    (IF(column LIKE '%bar%', 1, 0) + IF(column LIKE '%foo%', 1, 0)) AS score
FROM Items
WHERE column LIKE '%foo%' OR column LIKE '%bar%'
ORDER BY score DESC;

我的 SQL 有点生疏,但至少在 MySQL 5.0 中应该可以实现这样的操作。另请参阅该IF功能的手册:http: //dev.mysql.com/doc/refman/5.0/en/control-flow-functions.html

于 2008-09-17T02:47:08.987 回答
0

哪个数据库管理系统?

例如,它可以通过 CTE 或 Union 来完成,但如果你使用的是 MySQL,那么你可以忘记它。

于 2008-09-17T02:41:10.250 回答
0

试试这个代码:

SELECT * FROM Items WHERE column LIKE '%foo%' OR column LIKE '%bar%'
order by (select count(*) from items i where i.column= item.column) DESC 

如果您不关心细节, 您也可以按columnand分组。count(*)ORDER

于 2008-09-17T02:43:56.483 回答
0

您可能想试一试:

SELECT *
FROM Items
WHERE column LIKE '%foo%' OR column LIKE '%bar%'
ORDER BY CASE WHEN column LIKE '%foo%' AND column LIKE '%bar%' THEN 1 ELSE 0 END DESC

注意:这是干编码的,可能不是很便携。

于 2008-09-17T02:46:12.983 回答
0

由于您的查询当前正在编写,WHERE 子句不会为您提供任何可用于对结果进行排序的信息。我喜欢布赖恩的想法;添加一个常量列并联合查询,您甚至可以在一个结果集中获得所有内容。例如:

SELECT 1 as rank, * FROM Items WHERE column LIKE '%foo%' AND column LIKE '%bar%'
UNION
SELECT 2 as rank, * FROM Items WHERE column LIKE '%foo%' AND column NOT LIKE '%bar%'
UNION
SELECT 2 as rank, * FROM Items WHERE column LIKE '%bar%' AND column NOT LIKE '%foo%'
ORDER BY rank

但是,这只会给你这样的东西:

  • 匹配 foo 和匹配 bar 的所有行的无序集
  • 后面是(无序集)与 foo 或 bar 匹配的所有行,但不能同时匹配两者(尽管您可以在最后一个 SELECT 语句中使用不同的常量将其分成两个单独的组)。

这可能正是您要查找的内容,但它不会告诉您哪些行匹配 foo 三次,或者将它们排在仅包含一个 foo 实例的行之前。此外,所有这些 LIKE 都会变得昂贵。如果您真正想做的是根据相关性(无论您如何定义)对结果进行排序,那么最好使用全文索引。如果你使用的是 MS SQL Server,它有一个内置的服务可以做到这一点,也有第三方产品可以做到这一点。

编辑:在查看了所有其他答案之后(当我开始我的时候只有两个- 我显然必须学会更快地思考;-))很明显有几种方法可以解决这个问题,具体取决于你想要完成的事情。我建议您根据解决方案在您的系统上的表现来测试和比较解决方案. 我不是性能/调优专家,但函数往往会减慢速度,尤其是在您对函数的结果进行排序时。LIKE 运算符也不一定是敏捷的。作为开发人员,使用“IF”和“CASE”等熟悉的结构似乎很自然,但是使用更多基于集合的方法的查询通常在 RDMS 中具有更好的性能。同样,YMMV,所以最好测试一下你是否完全关心性能。

于 2008-09-17T03:19:06.743 回答
0

2个查询:

SELECT * FROM Items WHERE column LIKE '%foo%' AND column LIKE '%bar%';
SELECT * FROM Items WHERE (column LIKE '%foo%' AND column NOT LIKE '%bar%') OR (column NOT LIKE '%foo%' AND LIKE '%bar%')

(SQL 中没有异或)

于 2008-09-17T02:55:53.583 回答
0

并非所有 RDBMS 都支持 IF(或 Oracle 中的 DECODE)语句。如果不是,您可以使用子查询来定义表“a”并搜索所有员工的名为 JO SMITH 或组合。

SELECT 
 a.employee_id,
 a.surname,
 sum(a.counter)
FROM

 (SELECT
   employee_id,
   surname,
   1 as counter
  FROM
   MyTable
  WHERE
   surname like '%SMITH%'

  UNION ALL

  SELECT
   employee_id,
   surname,
   1 as counter
  FROM
   MyTable
  WHERE
   surname like '%JO%'
   ) a

GROUP BY 
 a.employee_id,
 a.surname
ORDER BY 3,1,2

确保你使用 UNION ALL 否则它将不起作用。您也可以使用 UPPER() 使您的搜索不区分大小写。

于 2008-09-17T03:00:04.073 回答