在子查询mysql上使用REGEXP vs IN

时间:2013-06-03 07:48:50

标签: mysql regex

我想使用表'similar'中的数据来查找表'releases'的结果

表'相似'具有此结构

artist  similar_artist
Moodymann   Theo Parrish
Moodymann   Jeff Mills
Moodymann   Marcellus Pittman
Moodymann   Rick Wilhite

到目前为止,我的查询是

SELECT * FROM releases
WHERE 
releases.all_artists REGEXP 'Moodymann'
OR releases.label_no_country='KDJ'
OR releases.all_artists IN (SELECT similar_artist 
                            FROM similar 
                            WHERE artist='Moodymann')
ORDER BY date DESC

列'all_artists'有这样的记录:

Moodymann | Theo Parrish | Rick Wade
Jeff Mills | Moodymann | Rick Wilhite

所以我想要的结束查询基本上就是这个

SELECT * FROM releases
    WHERE 
    releases.all_artists REGEXP 'Moodymann'
    OR releases.label_no_country='KDJ'
    OR releases.all_artists IN ('Theo Parrish','Jeff Mills','Marcellus Pittman','Rick Wilhite')

为了进行匹配,我认为我需要使用REGEXP而不是IN - REGEXP返回'Subquery返回超过1行'。如何使用从子查询返回的数据?

此外,查询需要很长时间才能运行(最多20秒) - 无论如何都要加快速度,因为这在我的网络应用中无法使用。

谢谢!

3 个答案:

答案 0 :(得分:3)

我知道如何将REGEXP与子查询一起使用的唯一方法是使用该子查询生成REGEXP字符串。

SELECT * FROM releases
WHERE 
releases.all_artists REGEXP 'Moodymann'
OR releases.label_no_country='KDJ'
OR releases.all_artists REGEXP (
   SELECT GROUP_CONCAT(similar_artist SEPARATOR '|') 
   FROM similar 
   WHERE artist='Moodymann' 
   GROUP BY similar_artist)
ORDER BY date DESC

上面没有经过测试,只是我可能尝试的理论。然而,它并不是最优的。

更新

此后对此进行了测试,发现GROUP BY similar_artist应为GROUP BY artist

SELECT * FROM releases
WHERE 
releases.all_artists REGEXP 'Moodymann'
OR releases.label_no_country='KDJ'
OR releases.all_artists REGEXP (
   SELECT GROUP_CONCAT(similar_artist SEPARATOR '|') 
   FROM similar 
   WHERE artist='Moodymann' 
   GROUP BY artist)
ORDER BY date DESC

然而,正如Pheonix所提到的,你最好将你的结构重构为releases_artist表。然后你可以通过JOIN来完成所有这些工作,这会更快,更快。

答案 1 :(得分:0)

试试这个SQL

SELECT * 
FROM releases
WHERE releases.all_artists LIKE '%Moodymann%'
OR releases.label_no_country='KDJ'
ORDER BY date DESC

SQL Fiddle

MySQL 5.5.30架构设置

CREATE TABLE Table1
    (`artist` varchar(9), `similar_artist` varchar(17))
;

INSERT INTO Table1
    (`artist`, `similar_artist`)
VALUES
    ('Moodymann', 'Theo Parrish'),
    ('Moodymann', 'Jeff Mills'),
    ('Moodymann', 'Marcellus Pittman'),
    ('Moodymann', 'Rick Wilhite')
;


create table allt(allf varchar(50));

insert into allt values('Moodymann | Theo Parrish | Rick Wade'),
('Jeff Mills | Moodymann | Rick Wilhite'),
('Jeff Mills | asdasdadasd | Rick Wilhite');

查询1

SELECT * 
FROM allt
WHERE allt.allf LIKE '%Moodymann%'

<强> Results

|                                  ALLF |
-----------------------------------------
|  Moodymann | Theo Parrish | Rick Wade |
| Jeff Mills | Moodymann | Rick Wilhite |

答案 2 :(得分:0)

您可以在逗号分隔列表上进行连接(不会很快,但可能比使用带有前导外卡的LIKE更快),并且您可以用逗号替换现有分隔符以允许此操作。此外,您还可以使用大量的UNION来使您的艺术家列表像表格一样进行连接。

此外,您可以使用union而不是其他WHERE子句,这可能有助于允许使用索引(MySQL在查询中每个表只使用一个索引,因此使用OR在不同的列上查询会强制它不使用它正在检查的列之一的索引。

因此,您可以执行以下操作: -

SELECT releases.* 
FROM releases
INNER JOIN (SELECT 'Theo Parrish' AS anArtist UNION SELECT 'Jeff Mills' UNION SELECT 'Marcellus Pittman' UNION SELECT 'Rick Wilhite') Sub1
ON FIND_IN_SET(Sub1.anArtist, REPLACE(releases.all_artists, " | ", ",")) > 0
UNION
SELECT releases.* 
FROM releases
WHERE releases.label_no_country='KDJ'

但是,如果更改数据库设计以将管道分隔的艺术家列表拆分到不同的表格上,则可以选择相反的方式。它会更快,并将应对更多的艺术家。