2012-05-25 186 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