2010-05-05 53 views
0

我有2個表格 - 包和項目。項目表包含屬於包的所有項目以及位置信息。就像下面的示例表:如何根據其他行返回結果集

Packages table 
id, type(enum{general,special}) 
1, general 
2, special 

Items table 
id, package_id, location 
1, 1, America 
2, 1, Europe 
3, 2, Europe 

問:我想找到屬於一個位置的所有「特別」套餐,如果沒有特殊的包被找到,那麼它應該返回屬於同一個位置「一般」的軟件包。

所以,

  1. 爲「歐洲」:包2應該,因爲它被退回是特殊的包(雖然包1也屬於歐洲,但因爲它的一般包裝不需要)

  2. 對於「美」:包1應當返還,因爲沒有特殊的包

+0

應該指出的是:「沒有這樣的假設,特殊的包裝有更高的IDS,我只是爲了清晰起見而製作了更小的表格。」 - 理解 – Senseful 2010-05-05 21:29:39

+0

@Eagle:我不明白爲什麼它會導致混淆,但澄清此外,軟件包表有超過'n'條目。每個條目都有一個ID和一個類型。類型可以是「一般」或「特殊」。 – understack 2010-05-05 21:45:15

+0

對不起,我誤解了這個問題。我想我現在明白了。我感到困惑與枚舉認爲它可能包含超過2個不同的值。 – Senseful 2010-05-05 22:31:27

回答

1

這裏有兩個不同的解決方案:(注:我叫枚舉場「package_t YPE「)

第一溶液(通過IF()函數):

select 
    i.location, 
    if(ps.id is not null, ps.id, pg.id) as package_id 
from 
    (select distinct location from Items) i 
    inner join 
    (select i.location, p.id 
    from Items i 
     inner join Packages p on (i.package_id = p.id and p.package_type = 'general') 
    ) pg on (i.location = pg.location) 
    left join 
    (select i.location, p.id 
    from Items i 
     inner join Packages p on (i.package_id = p.id and p.package_type = 'special') 
    ) ps on (i.location = ps.location) 

該溶液基本上需要的位置,並將其加入到封裝與一般(其被假定爲存在;因此inner join)和特殊包裝(這是可選的;因此left join)。它創造的記錄,如本:

location | general-package | [special-package] 

它然後使用MySQL IF功能的第一次嘗試選擇特殊包的ID,然後回落到普通包的ID。

第二溶液(通過枚舉的鑄造到整數):

select i.location, p.id 
from 
    (select i.location, max(cast(package_type as unsigned)) as package_type 
    from Items i 
    left join Packages p on (i.package_id = p.id) 
    group by location 
) i 
    inner join 
    (select i.location, p.id, p.package_type 
    from Items i 
     inner join Packages p on (i.package_id = p.id) 
    ) p on (i.location = p.location and i.package_type = p.package_type) 

將該溶液利用了Enum也被存儲爲整數的事實。它將枚舉轉換爲整數。 special在這種情況下將返回2general將返回1。因爲在這種情況下這些特殊值保證高於一般值(即2> 1),所以我們可以使用MAX聚合函數。現在我們基本上有一張地點表和他們的「推薦套餐」(如果存在的話,一般情況下是特殊的)。我們只需將它與預期的包類型一起加入到普通查詢中,並返回正確的結果。

聲明:我不確定這些方法的效率,所以你可能想自己測試一下。


如果你正在尋找要麼重新設計表或進行非規範化以提高效率,我覺得這樣的設計可能更適合:

GeneralPackages table 
id, name 
1, General Package 1 

SpecialPackages table 
id, name 
1, Special Package 1 
2, Special Package 2 

Items table 
id, general_package_id, special_package_id, location 
1, 1, NULL, America 
2, 1, 2, Europe 

的好處是,它更容易執行

  • 一個位置必須始終有一個大致的包(Items.general_package_id可以被定義爲NOT NULL)
  • :在數據庫級別的幾個規則
  • 一個位置必須只有一個通用包(在域中添加它,而不是連接保證只有一個指定)
  • 一個位置最多隻能包含一個特殊包(將其添加到一個字段中而不是一個連接保證只有一個指定)
  • Items.general_package_id = GeneralPackages.id上的外鍵將保證該列只包含「普通」的有效包。
  • 對於special_package_id可以做同樣的事情。

缺點是您每次使用舊查詢時都可能需要使用UNION ALL。