SQL:查找行并根据匹配列的数量进行排序?

Kir*_*lla 3 mysql sql

让我们想象一下,我们有一个结构如此简单的“汽车”表......

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;因此,其总和将是匹配的数量。


Tom*_*lak 5

效率不高,但是...

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)