让我们想象一下,我们正在拥有如此简单结构的“汽车”牌桌......
car_id INT
color ENUM('black','white','blue')
weight ENUM('light','medium','heavy')
type ENUM('van','sedan','limo')
拳头,我正在选择汽车(1,黑色,重型,豪华轿车),然后我想获得按匹配列数排序的相关汽车列表(没有任何列重量)。所以,首先我期待看到(黑色,重型,豪华轿车)汽车,然后我期待看到只有2个匹配领域的汽车等。
是否可以使用SQL执行这种排序?
对不起我的英语,但我真的希望我的问题很清楚。
谢谢。
答案 0 :(得分:4)
效率不高,但是......
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
这对大型数据集的运行速度不会很快,因为JOIN和ORDER BY都不能使用索引。很可能存在更优化的版本。
我的测试设置上的输出如下所示:
e_car_id e_color e_weight e_type r_car_id r_color r_weight r_type rank 1 black heavy limo 7 black heavy limo 3 1 black heavy limo 2 black light limo 2 1 black heavy limo 3 black heavy van 2 1 black heavy limo 4 black medium van 1 1 black heavy limo 5 blue light limo 1
答案 1 :(得分:2)
可能有几种方法可以优化子查询,但不使用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
输出:
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
答案 2 :(得分:1)
我知道这是一个老问题,但是您应该可以将表达式包装在括号中以对其进行评估
SELECT *
FROM `cars`
WHERE `color` = "black"
OR `weight` = "heavy"
OR `type` = "limo"
ORDER BY ( (`color` = "black")
+ (`weight` = "heavy")
+ (`type` = "limo")
) DESC
括号内的每个表达式如果为true,则等于1,如果为false,则等于0;因此总和就是匹配的数量。
答案 3 :(得分:0)
mysql> select * from cars;
+--------+-------+--------+-------+
| car_id | color | weight | type |
+--------+-------+--------+-------+
| 1 | black | light | van |
| 2 | black | light | sedan |
| 3 | black | light | limo |
| 4 | black | medium | van |
| 5 | black | medium | sedan |
| 6 | black | medium | limo |
| 7 | black | heavy | van |
| 8 | black | heavy | sedan |
| 9 | black | heavy | limo |
| 10 | white | light | van |
| 11 | white | light | sedan |
| 12 | white | light | limo |
| 13 | white | medium | van |
| 14 | white | medium | sedan |
| 15 | white | medium | limo |
| 16 | white | heavy | van |
| 17 | white | heavy | sedan |
| 18 | white | heavy | limo |
| 19 | blue | light | van |
| 20 | blue | light | sedan |
| 21 | blue | light | limo |
| 22 | blue | medium | van |
| 23 | blue | medium | sedan |
| 24 | blue | medium | limo |
| 25 | blue | heavy | van |
| 26 | blue | heavy | sedan |
| 27 | blue | heavy | limo |
+--------+-------+--------+-------+
27 rows in set (0.00 sec)
select *,
(case
when color = 'black' and weight = 'heavy' and type = 'limo'
then 3
when ( color = 'black' and type = 'limo') or
(color = 'black' and weight = 'heavy') or
(weight = 'heavy' and type = 'limo')
then 2
else 1
end) sort_order
from cars
where color = 'black' or weight = 'heavy' or type = 'limo'
order by sort_order desc;
+--------+-------+--------+-------+------------+
| car_id | color | weight | type | sort_order |
+--------+-------+--------+-------+------------+
| 9 | black | heavy | limo | 3 |
| 27 | blue | heavy | limo | 2 |
| 18 | white | heavy | limo | 2 |
| 8 | black | heavy | sedan | 2 |
| 7 | black | heavy | van | 2 |
| 6 | black | medium | limo | 2 |
| 3 | black | light | limo | 2 |
| 24 | blue | medium | limo | 1 |
| 25 | blue | heavy | van | 1 |
| 21 | blue | light | limo | 1 |
| 26 | blue | heavy | sedan | 1 |
| 17 | white | heavy | sedan | 1 |
| 16 | white | heavy | van | 1 |
| 15 | white | medium | limo | 1 |
| 12 | white | light | limo | 1 |
| 5 | black | medium | sedan | 1 |
| 4 | black | medium | van | 1 |
| 2 | black | light | sedan | 1 |
| 1 | black | light | van | 1 |
+--------+-------+--------+-------+------------+
19 rows in set (0.00 sec)