2014-03-05 21 views
0

我熟悉「LEFT JOIN/IS NULL」成語以獲得MySQL中MINUS運算符的等效項。不過,我一直在試圖解決這一一會兒沒有成功(短醜子選擇的)MySQL在兩個左連接之間的就地MINUS

下面是一個樣本結果集來說明這個問題:

+-------------------+----------------------------------------------+-----------+ 
| group_id   | valid          | not_valid | 
+-------------------+----------------------------------------------+-----------+ 
| favorites   | AD12,AD17,AD10,AD15,AD13,AD18,AD11,AD16,AD14 | NULL  | 
| fruits_veggies | AD13           | NULL  | 
| pizza_grill  | AD12,AD10,AD21,AD19,AD11,AD22,AD20   | NULL  | 
| salsa_wraps  | NULL           | NULL  | 
| student_beverages | AD32,AD30,AD31        | AD31,AD30 | 
+-------------------+----------------------------------------------+-----------+ 

在上面,我想從「有效」列中刪除任何值也存在於「not_valid」,所以AD31,AD30應該消失,只留下AD32,所以一個經典的MINUS運算符:)

這是SQL給我的以上結果集。任何想法如何擴展它以消除有效SKU中的所有無效SKU?

select 
    gm.group_id, 
    group_concat(pt_include.sku) valid, 
    group_concat(pt_exclude.sku) not_valid 

from main_menu mm 

    left join group_membership gm on 
     mm.master_account_id = gm.master_account_id 
     and mm.group_id = gm.group_id 

    left join product_tag pt_include on 
     mm.master_account_id = pt_include.master_account_id 
     and gm.tag = pt_include.tag and gm.inclusive = '+' 

    left join product_tag pt_exclude on 
     mm.master_account_id = pt_exclude.master_account_id 
     and gm.tag = pt_exclude.tag and gm.inclusive = '-' 

where 
    mm.master_account_id = 321 
    and mm.menu_id = 987 

group by gm.group_id 

追問:

下面我刪除所有其他數據的簡潔。考慮一個產品可以被標記爲X,Y,Z.目標是找回標記爲「X」&「Y」但不是「Z」的項目。可以有任何數量的「包含」或「獨佔」標籤。用戶輸入類似+ X,+ Y,-Z的東西。

在我們的示例中,我們希望找回標記爲飲料的所有產品,但如果飲料爲'teacher_only'則排除。因此,這兩個連接表示這兩組:首先加入所有飲料,然後加入所有飲料& teacher_only。最終結果應該是首先加入MINUS第二次加入。

mysql> select * from main_menu; 
+-------------------+------------------------+-------------------+ 
| master_account_id | menu_id    | group_id   | 
+-------------------+------------------------+-------------------+ 
| FA32113145  | 1231     | student_beverages | 
+-------------------+------------------------+-------------------+ 

mysql> select * from group_membership; 
+-------------------+-------------------+--------------+-----------+ 
| master_account_id | group_id   | tag   | inclusive | 
+-------------------+-------------------+--------------+-----------+ 
| FA32113145  | student_beverages | beverage  | +   | 
| FA32113145  | student_beverages | teacher_only | -   | 
+-------------------+-------------------+--------------+-----------+ 

mysql> select * from product_tag; 
+-------------------+------+--------------+ 
| master_account_id | sku | tag   | 
+-------------------+------+--------------+ 
| FA32113145  | AD30 | beverage  | 
| FA32113145  | AD30 | teacher_only | 
| FA32113145  | AD31 | beverage  | 
| FA32113145  | AD31 | teacher_only | 
| FA32113145  | AD32 | beverage  | 
+-------------------+------+--------------+ 
+0

你存儲在一個字段逗號分隔值??? – jtate

+0

不,我只是說明了兩個集合的內容,即pt_include和pt_exclude,因此您知道我想從另一個排除哪些值。 – Debriter

回答

0

您不需要兩次連接。只需使用條件聚合。 group_concat()將忽略NULL參數,所以你可以只使用一個case語句TIS:

select gm.group_id, 
     group_concat(case when gm.inclusive = '+' then pt.sku end) as valid, 
     group_concat(case when gm.inclusive = '-' then pt.sku end) as not_valid 
from main_menu mm left join 
    group_membership gm 
    on mm.master_account_id = gm.master_account_id and 
     mm.group_id = gm.group_id left join 
    product_tag pt 
    on mm.master_account_id = pt.master_account_id and 
     gm.tag = pt.tag and gm.inclusive = '+' 
where mm.master_account_id = 321 and 
     mm.menu_id = 987 
group by gm.group_id; 

編輯:

哦,原來是你有兩種類型的標籤,-+標籤問題,在這種情況下,您只需要-列中的標籤。我會首先通過sku合計接近這個,然後由集團:

select gm.group_id, 
     group_concat(case when includeplus = 1 and includeminus = 0 then sku end) as valid, 
     group_concat(case when includeminus = 1 then sku end) as invalid 
from (select gm.group_id, pt.sku, 
      max(gm.include = '+') then includeplus, 
      max(gm.include = '-') then includeminus 
     from main_menu mm left join 
      group_membership gm 
      on mm.master_account_id = gm.master_account_id and 
       mm.group_id = gm.group_id left join 
      product_tag pt 
      on mm.master_account_id = pt.master_account_id and 
       gm.tag = pt.tag and gm.inclusive = '+' 
     where mm.master_account_id = 321 and 
      mm.menu_id = 987 
     group by gm.group_id, pt.sku 
    ) g 
group by gm.group_id; 
+0

不幸的是,這是行不通的。產品可以有(無限制)標籤,例如「飲料」,「教師唯一」等。我們想要回來的是所有產品是「飲料」減去「teacher_only」。 mysql> select * from product_tag; + ------------------- + ------ + -------------- + | account_id | sku |標籤| + ------------------- + ------ + -------------- + | 123 | AD30 |飲料| | 123 | AD31 |飲料| | 123 | AD32 |飲料| | 123 | AD30 | teacher_only | | 123 | AD31 | teacher_only | – Debriter

+0

@Debriter。 。 。我不明白你的評論。你能用數據編輯你的問題嗎?產生你給定的結果? –