2010-01-21 106 views
2

讓我們想象一下,我們有「汽車」表這樣簡單的結構......SQL:查找行並根據匹配列數進行排序?

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

拳,我選擇的汽車(1,黑,重,豪華轎車),那麼我想根據匹配列的數量(沒有任何列重量)獲取相關汽車列表。所以,首先我期待看到(黑色,重型,豪華轎車)汽車,然後我期待看到只有兩個匹配字段的汽車等。

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

對不起我的英文,但我真的很希望我的問題對你很清楚。

謝謝。

+0

這真的很難理解。汽車有什麼關係? – Codesleuth 2010-01-21 09:50:30

+0

我相信他會選擇一條記錄,然後比較所有其他記錄並計算每條記錄匹配字段的數量。然後他想按照匹配的字段數來排序記錄(是相同的)。所以基本上按照與所選記錄相似性進行排序。 – sleske 2010-01-21 09:53:19

+0

@sleske:我仍然感到困惑,我會讓你回答這個問題:P – Codesleuth 2010-01-21 10:05:56

回答

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 
+0

絕對好,請給我一些時間來了解這種結構。 – Kirzilla 2010-01-21 10:53:52

+0

基本上你會得到一張按顏色匹配的汽車列表,按重量匹配的汽車列表以及按類型匹配的汽車列表。將這三個列表聯合起來,按顏色,重量和類型分組。每個組中的記錄數量都會爲您提供相關性,因爲三輛汽車出現在三個列表中的車輛越多,匹配的屬性就越多。其餘部分僅用於格式化目的。 – 2010-01-21 11:28:34

+0

謝謝你的完整解釋! – Kirzilla 2010-01-21 11:36:44

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 

大型數據集這不會跑得很快,因爲無論是加盟還是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 
+0

絕對好,請給我一些時間來理解這種結構。 – Kirzilla 2010-01-21 11:10:40

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)