2012-05-25 145 views
0

我試圖構建一個查詢,這讓我瘋狂。我不知道從哪裏開始解決這個問題,但是在搜索了一下之後,我開始玩子查詢。現在我處於不確定這是否能解決我的問題,或者如果能解決我的問題,如何創建一個我想要的。MySQL查詢匹配無關條款

這是我當前表的一個非常簡單的視圖(稱之爲tbl_1):

--------------------------------- 
| row | name | other_names | 
|-------------------------------| 
| 1 | A | B, C  | 
| 2 | B | C   | 
| 3 | A | C   | 
| 4 | D | E   | 
| 5 | C | A, B  | 
--------------------------------- 

一些我的工作的項目有多個名稱(品牌名稱,名稱在其他國家,代號,等等),但最終所有這些不同的名稱都指向同一個項目。我本來正在運行的線沿線的搜索查詢:這將返回行1和3。但是

SELECT * FROM tbl_1 
WHERE name LIKE '%A%' 
OR other_names LIKE '%A%'; 

,我很快就意識到,我的查詢也應該返回行2,如A = B = C.將如何我去做類似的事情?我願意接受一些奇怪的查詢之外的替代建議,例如構建另一個表格,它將所有名稱合併到一行中,但我認爲這樣會容易出錯或效率低下。

此外,我使用InnoDB和其他用PHP和Python編寫的代碼運行MySQL 5.5.23。

謝謝!

更新12年5月26日:
我回到我原來使用子查詢的思維,但權當我以爲我要去哪裏我遇到了一個記錄MySQL的問題,即查詢是否從評估外面在和我的子查詢將被評估爲每一行,並不會在現實的時間內完成。這裏就是我試圖做的事:

SELECT * FROM tbl_1 
WHERE name = ANY 
    (SELECT name FROM tbl_1 WHERE other_names LIKE '%A%' or name LIKE '%A%') 
OR other_names = ANY 
    (SELECT name FROM tbl_1 WHERE other_names LIKE '%A%' or name LIKE '%A%') 

它返回我想用什麼樣的示例表,但上述的MySQL問題/錯誤導致被認爲是一個關聯查詢,而不是一個獨立的子查詢。因此,我無法在真正的表(〜250,000行)上測試查詢,因爲它最終超時。

我讀過這個問題的主要解決方法是使用連接而不是子查詢,但我不知道我將如何應用到我想要做的。我考慮的越多,我可能會更好地使用PHP/Python獨立運行子查詢,並使用結果數組來創建我想要的主查詢。然而,我仍然認爲有可能錯過一些結果,因爲列中的術語並不像我的例子那麼好(一些術語是多個單詞,一些是括號,其他名稱不一定是逗號,分開等)。

另外,我在考慮構建一個單獨的表,將建立必要的聯繫,是這樣的:

| 1 | A | B, C| 
| 2 | B | C, A| 
| 3 | C | A, B| 

,但我認爲這是一個很大談何容易考慮到我的工作中的數據以及它存在的非標準格式。

我在這一點上強烈考慮的路線是建立一個易於構建的鏈接的獨立表格(即name:other_names的比例爲1:1),所以我不必處理格式化other_names列中存在的問題。我還可以消除/限制LIKE的使用,並要求用戶至少知道一個確切的名稱,以便簡化結果並可能提高總體性能。

總之,我討厭使用我無法控制的輸入數據。

+0

只是想了解表結構,如果B實際上只是A的另一個名稱,而不是爲什麼它有一個單獨的行(第2行)? – coder

+0

@coder行中的數據由用戶填充,用戶不必知道某些內容的所有名稱。更具體地說,這些名稱是指藥物產品。一個人可能知道美國的Incivek = telaprevir,並將其輸入(名稱爲Incivek,其他名稱爲telaprevir),但在歐洲也稱爲Incivo。因此,一個人可能正在搜索'Incivek',但它也應該爲Incivo調出結果。 – Tim

回答

0

我想不出一個支持無限深名稱身份的查詢。但是,如果你可以用「遞歸」有限數量的工作,你可以考慮使用一個類似的查詢,從您提供的查詢,檢索所有行與名身份:

SELECT a.* FROM tbl_1 a 
WHERE a.name='A' 
OR a.other_names LIKE '%A%' 
UNION 
SELECT b.* FROM tbl_1 a 
JOIN tbl_1 b ON a.other_names LIKE '%' || b.name || '%' OR b.other_names LIKE '%' || a.name || '%' 
WHERE a.name='A' 
OR a.other_names LIKE '%A%'; 

該查詢將返回第2行,但它不會在您的示例中返回任何具有「B」作爲「other_name」的附加行。所以,你就必須聯合其他查詢:

SELECT a.* FROM tbl_1 a 
WHERE a.name='A' 
OR a.other_names LIKE '%A%' 
UNION 
SELECT b.* FROM tbl_1 a 
JOIN tbl_1 b ON a.other_names LIKE '%' || b.name || '%' OR b.other_names LIKE '%' || a.name || '%' 
WHERE a.name='A' 
OR a.other_names LIKE '%A%'; 
UNION 
SELECT c.* FROM tbl_1 a 
JOIN tbl_1 b ON (a.other_names LIKE '%' || b.name || '%' OR b.other_names LIKE '%' || a.name || '%') 
JOIN tbl_1 c ON (b.other_names LIKE '%' || c.name || '%' OR c.other_names LIKE '%' || b.name || '%') 
WHERE a.name='A' 
OR a.other_names LIKE '%A%'; 

正如你所看到的,查詢將增長,隨深度增加而迅速加快,而這還不算什麼,我會叫美麗。但它可能適合您的需求。我並不是很熟練使用MySQL函數,但我想您可以創建一個更優雅的解決方案,並使用這些解決方案進行無限深度的處理。你也可以考慮用Python編程解決這個問題。

+0

謝謝!由於實際問題(我的表格有超過200,000行),這並不能真正解決我的問題,但是您提到遞歸使我很快意識到這實際上有多困難。在這一點上,我想我會嘗試使用python來處理輸入數據,並創建一個包含所有正確鏈接的單獨表格。 – Tim

1

偶然發現了這個問題,所以我不知道我的建議是否相關,但這看起來像「聯合發現」這樣的東西的好用法。

SELECT將非常容易和快速。 但插入&更新relativly複雜,你可能會需要一個在代碼迴路(而更新的行> 0),......和幾個DATABSE調用

示例表:

--------------------------- 
| row | name | group | 
|-------------------------| 
| 1 | A | 1 | 
| 2 | B | 1 | 
| 4 | C | 1 | 
| 5 | D | 2 | 
| 6 | X | 1 | 
| 7 | Z | 2 | 
--------------------------- 

選擇: SELECT姓名FROM tbl WHERE group =(SELECT group FROM tbl WHERE name LIKE '%A%')


插入關係K = T:(psedu編碼..)

SELECT group as gk WHERE name = K; SELECT group as gt WHERE name = T;

如果(GK空結果)和(GT空結果)以及新的組插入兩

--------------------------- 
| row | name | group | 
|-------------------------| 
| 1 | A | 1 | 
| 2 | B | 1 | 
| 4 | C | 1 | 
| 5 | D | 2 | 
| 6 | X | 1 | 
| 7 | Z | 2 | 
| 8 | K | 3 | 
| 9 | T | 3 | 
--------------------------- 

如果(GK空結果)和(GT NOT空結果)插入噸用基團= gx.group

--------------------------- 
| row | name | group | 
|-------------------------| 
| 1 | A | 1 | 
| 2 | B | 1 | 
| 4 | C | 1 | 
| 5 | D | 2 | 
| 6 | X | 1 | 
| 7 | Z | 2 | 
| 8 | K | 2 | 
| 9 | T | 2 | 
--------------------------- 

(在另一種情況下是相同的)

和當兩個不爲空,更新一個組是其他

更新tbl1 SET group = gt WHERE group = gk