2014-04-02 66 views
2

我存儲目的地用戶是願意爲varchar領域推出一款產品是這樣的:MySql的逗號分隔值,並使用IN選擇數據

"userId" "destinations" "product" 
"1"  "US,SE,DE"  "apples" 
"2"  "US,SE"  "books" 
"3"  "US"   "mushrooms" 
"1"  "SE,DE"  "figs" 
"2"  "UK"   "Golf Balls" 

我希望這個查詢將返回所有行US在場。相反,它只返回一行。

select * from destinations where destinations IN('US'); 

我該如何解決這個問題?我是否使用錯誤的列類型?或者它是我的查詢失敗。

當前結果

US 

預期結果

US,SE,DE 
US,SE 
US 
+1

首先正常化數據 – Strawberry

+0

我建議你把目的地爲表內的'[..]'像字符'[美國] [SE] [德] '然後你可以通過執行'SELECT * FROM destinations where'destination LIKE('%[US]%')來獲得包含'US'的記錄。'' –

+0

@Strawberry每一行都屬於一個特定的用戶。 UserId 1將發貨到美國,東南,德國等等。 – Norman

回答

3

嘗試用FIND_IN_SET

select * from destinations where FIND_IN_SET('US',destinations); 
+1

你是對的!道歉! – Strawberry

+1

+1有趣的解決方案。但是,問題在於,當您將國家/地區添加到搜索中時,必須將查詢與其他FIND_IN_SET匹配組合起來。這對於演出來說很糟糕 –

1

不幸的是,你的結構表中的方式,你必須檢查的「美國模式匹配「在你的字符串開頭,中間或結束。你能做到這一點

一種方法是使用類似如下:

SELECT * 
FROM destinations 
WHERE destinations LIKE ('%US%'); 

另一種方法是使用REGEXP:

SELECT * 
FROM destinations 
WHERE destinations REGEXP '.*US.*'; 

另一種是使用FIND_IN_SET,由Sadkhasan解釋。

CAVEAT

這一切都不會提供了極大的性能或數據的完整性,雖然。當您將搜索條件添加到標準時,他們將全部實現其性能問題。

E.g.使用FIND_IN_SET,由Sadkhasan建議,你會做這樣的事情:

SELECT * FROM destinations 
WHERE FIND_IN_SET('US',destinations) 
    OR FIND_IN_SET('CA',destinations) 
    OR FIND_IN_SET('ET',destinations); 

使用REGEXP好一點,雖然REGEXP是天生的慢:

SELECT * 
FROM destinations 
WHERE destinations REGEXP '.*US|CA|ET.*'; 

那現在?

你最好的選擇將被切換到3NF設計,通過拆分申請產品分爲2代表的目的地,你可以加入,例如:

CREATE TABLE products (
    id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, 
    userId INT NOT NULL REFERENCES users(id), 
    name VARCHAR(255) NOT NULL 
) TYPE=InnoDB; 

,那麼你會添加什麼叫做複合鍵的表,每行包含一個productId和一個國家,每個國家一行。

CREATE TABLE product_destinations (
    productId INT NOT NULL REFERENCES products(id), 
    country VARCHAR(2) NOT NULL, 
    PRIARY KEY (productId, country) 
) TYPE=InnoDB; 

本表數據看起來像:

productId | country 
----------|-------- 
     1 | US 
     1 | CA 
     1 | ET 
     2 | US 
     2 | GB 

然後,你可以構建這樣的查詢:

SELECT p.* 
FROM products AS p 
    INNER JOIN product_destinations AS d 
     ON p.id = d.productId 
WHERE d.country IN ('US', 'CA', 'ET') 
GROUP BY p.id; 

它在SELECT重要添加組(或DISTINCT條款),因爲單個產品可能會出貨給多個國家,導致多行匹配 - 彙總會將這些數據減少爲每個產品ID的單個結果。

一個額外的好處是你不必更新你的國家列和做字符串操作,以確定該國是否已經存在。你可以讓數據庫爲你做,並插入 - 防止鎖定問題,這將進一步複合你的問題。

+1

如果只包含'US',該怎麼辦?這段代碼不檢索它,是嗎? –

+1

我可以做出改變,因爲這是開始。你在暗示什麼? – Norman

+0

我強烈建議您閱讀3NF設計,並以這種方式構建您的數據庫,以優化性能以及數據完整性。 –

0

你可以使用這個,如果你的目標只有兩個國家的caracters。

SELECT * FROM destinations WHERE destinations LIKE ('%US%') 

添加其他國家

SELECT * FROM destinations WHERE destinations LIKE ('%US%') 
           AND destinations LIKE ('%SE%') 
           ^^^--> you use AND or OR as you want the result.