簡體   English   中英

SQL:查找行並根據匹配列的數量排序?

[英]SQL : find rows and sort according to number of matching columns?

假設我們有一個具有如此簡單結構的“汽車”表...

car_id INT
color ENUM('black','white','blue')
weight ENUM('light','medium','heavy')
type ENUM('van','sedan','limo')

拳頭,我要選擇汽車(1,黑色,重型,豪華轎車),然后我想獲得相關汽車的列表,這些列表按匹配列的數量排序(無任何列重)。 所以,首先我希望看到(黑色,重型,豪華轎車)汽車,然后我希望看到只有2個匹配字段的汽車,等等。

是否可以使用SQL執行這種排序?

對不起,我的英語,但是我真的希望我的問題對您很清楚。

謝謝。

效率不高,但是...

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

可能有幾種方法可以優化子查詢,但是不使用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

我知道這是一個老問題,但是您應該可以將表達式包裝在括號中以對其求值

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; 因此,總和就是匹配的數量。

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)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM