让我们想象一下,我们有一个结构如此简单的“汽车”表......
car_id INT
color ENUM('black','white','blue')
weight ENUM('light','medium','heavy')
type ENUM('van','sedan','limo')
Run Code Online (Sandbox Code Playgroud)
拳头,我选择汽车(1,黑色,重型,豪华轿车),然后我想获得按匹配列数排序的相关汽车列表(没有任何列权重)。所以,首先我期待看到(黑色、重型、豪华轿车)汽车,然后我期待看到只有 2 个匹配字段等的汽车。
是否可以使用 SQL 执行这种排序?
对不起我的英语,但我真的希望我的问题对你来说很清楚。
谢谢你。
小智 7
我知道这是一个老问题,但是您应该能够将表达式括在括号中以对其进行求值
SELECT *
FROM `cars`
WHERE `color` = "black"
OR `weight` = "heavy"
OR `type` = "limo"
ORDER BY ( (`color` = "black")
+ (`weight` = "heavy")
+ (`type` = "limo")
) DESC
Run Code Online (Sandbox Code Playgroud)
括号内的每个表达式如果为真则等于 1,如果为假则等于 0;因此,其总和将是匹配的数量。
效率不高,但是...
SELECT
exact.car_id AS e_car_id, exact.color AS e_color,
exact.weight AS e_weight, exact.type AS e_type,
related.car_id AS r_car_id, related.color AS r_color,
related.weight AS r_weight, related.type AS r_type,
CASE WHEN related.color = exact.color THEN 1 ELSE 0 END
+ CASE WHEN related.weight = exact.weight THEN 1 ELSE 0 END
+ CASE WHEN related.type = exact.type THEN 1 ELSE 0 END
AS rank
FROM
cars AS exact
INNER JOIN cars AS related ON (
related.car_id <> exact.car_id
AND CASE WHEN related.color = exact.color THEN 1 ELSE 0 END
+ CASE WHEN related.weight = exact.weight THEN 1 ELSE 0 END
+ CASE WHEN related.type = exact.type THEN 1 ELSE 0 END
>= 1
)
WHERE
exact.car_id = 1 /* black, heavy, limo */
ORDER BY
rank DESC
Run Code Online (Sandbox Code Playgroud)
这不会在大型数据集上运行得非常快,因为 JOIN 和 ORDER BY 都不能使用索引。很可能存在更优化的版本。
我的测试设置上的输出如下所示:
e_car_id e_color e_weight e_type r_car_id r_color r_weight r_type rank 1 黑色重型豪华轿车 7 黑色重型豪华轿车 3 1 黑色重型豪华轿车 2 黑色轻型豪华轿车 2 1 黑色重型豪华轿车 3 黑色重型面包车 2 1 辆黑色重型豪华轿车 4 辆黑色中型面包车 1 1 黑色重型豪华轿车 5 蓝色轻型豪华轿车 1
小智 3
可能有几种方法可以优化子查询,但不使用case语句或次优连接子句:
select
*
from
(
select
selection.CarId,
selection.Colour,
selection.Weight,
selection.Type,
3 as Relevance
from
tblCars as selection
where
selection.Colour = 'black' and selection.Weight = 'light' and selection.Type = 'van'
union all
select
cars.CarId,
cars.Colour,
cars.Weight,
cars.Type,
count(*) as Relevance
from
tblCars as cars
inner join
(
select
byColour.CarId
from
tblCars as cars
inner join
tblCars as byColour
on
cars.Colour = byColour.Colour
where
cars.Colour = 'black' and cars.Weight = 'light' and cars.Type = 'van'
and
byColour.CarId <> cars.CarId
union all
select
byWeight.CarId
from
tblCars as cars
inner join
tblCars as byWeight
on
cars.Weight = byWeight.Weight
where
cars.Colour = 'black' and cars.Weight = 'light' and cars.Type = 'van'
and
byWeight.CarId <> cars.CarId
union all
select
byType.CarId
from
tblCars as cars
inner join
tblCars as byType
on
cars.Type = byType.Type
where
cars.Colour = 'black' and cars.Weight = 'light' and cars.Type = 'van'
and
byType.CarId <> cars.CarId
) as matches
on
cars.CarId = matches.CarId
group by
cars.CarId,
cars.Colour,
cars.Weight,
cars.Type
) as results
order by
Relevance desc
Run Code Online (Sandbox Code Playgroud)
输出:
CarId Colour Weight Type Relevance
1 black light van 3
3 white light van 2
4 blue light van 2
5 black medium van 2
6 white medium van 1
7 blue medium van 1
8 black heavy limo 1
Run Code Online (Sandbox Code Playgroud)