我试图构建一个让我疯狂的查询。我不知道从哪里开始解决它,但在搜索了一下后我开始玩子查询。现在,我不确定这是否会解决我的问题,或者如果能解决问题,如何创建一个能满足我想要的问题。
这是我当前表格的简单视图(称之为tbl_1):
---------------------------------
| row | name | other_names |
|-------------------------------|
| 1 | A | B, C |
| 2 | B | C |
| 3 | A | C |
| 4 | D | E |
| 5 | C | A, B |
---------------------------------
我正在使用的一些项目有多个名称(品牌名称,其他国家/地区的名称,代码名称等),但最终所有这些不同的名称都指向同一项目。我最初是按照以下方式运行搜索查询:
SELECT * FROM tbl_1
WHERE name LIKE '%A%'
OR other_names LIKE '%A%';
哪个会返回第1行和第3行。但是,我很快意识到我的查询也应该返回第2行,因为A = B = C.我怎么会这样做呢?我可以在花哨的查询之外接受其他建议,例如构建另一个表格,以某种方式将所有名称组合成一行,但我认为这样的内容会容易出错或效率低下。
此外,我使用InnoDB和其他用PHP和Python编写的代码运行MySQL 5.5.23。
谢谢!
更新5/26/12:
我回到了我最初使用子查询的想法,但是当我认为我到达某个地方时,我遇到了一个记录在案的MySQL问题,其中查询是从外部进行评估的,我的子查询将针对每一行进行评估并赢得&#39 ; t在一段合理的时间内完成。这就是我试图做的事情:
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|
但我认为考虑到我正在使用的数据以及存在的非标准化格式,说起来容易做起来难得多。
我在这一点上强烈考虑的路线是建立一个单独的表格,其中包含易于构建的链接(即名称:other_names的比例为1:1),因此我不必处理与other_names列中存在的格式问题。我也可以消除/限制LIKE的使用,并要求用户至少知道一个确切的名称,以简化结果,并可能提高整体性能。
总之,我讨厌使用我无法控制的输入数据。
答案 0 :(得分:1)
偶然发现了这个问题,所以我不知道我的建议是否相关,但这看起来像是“联合发现”这样的好用法。
SELECT非常简单快捷。 但插入&更新相对复杂,你可能需要一个内码循环(更新的行> 0)......和几个数据库调用
表格示例:
---------------------------
| row | name | group |
|-------------------------|
| 1 | A | 1 |
| 2 | B | 1 |
| 4 | C | 1 |
| 5 | D | 2 |
| 6 | X | 1 |
| 7 | Z | 2 |
---------------------------
选择:
SELECT name FROM tbl
WHERE group
=(SELECT group
FROM tbl
WHERE name
LIKE'%A%')
插入关系K = T :( psedu codeish ..)
SELECT group
as gk WHERE name = K;
选择group
作为gt WHERE name = T;
if(gk empty result)和(gt empty result)同时插入新组
---------------------------
| 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 |
---------------------------
if(gk empty result)和(gt NOT empty result)insert t with group = 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组= gt WHERE group = gk
答案 1 :(得分: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以编程方式解决问题。