如何在JOIN语句的WHERE中使用MySQL REGEXP

时间:2018-02-10 18:54:55

标签: mysql sql regex

我有两张桌子A和B. 表A包含列:ID和POST 表B包含列:ID,POST_ID和UPPERS

我想选择a.POST与正则表达式匹配的所有记录

'\\[cd(i|b)?(=[a-z0-9]+)?\\].+\\[/cd(i|b)?\\]' 

和JOIN表B在a.ID = b.POST_ID上,其中b.UPPERS与正则表达式匹配

'(\\|[0-9]+\\![0-9]{4}[-]+[0-9]{2}[-]+[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2},){1,}' 

我想出了以下语句,但即使列包含与正则表达式匹配的内容,它也不返回任何行

SELECT a.*,b.* 
FROM a JOIN
     b 
     ON b.POST_ID=a.ID 
WHERE a.POST RLIKE '\\[cd(i|b)?(=[a-z0-9]+)?\\].+\\[/cd(i|b)?\\]' AND
      b.UPPERS REGEXP '(\\|[0-9]+\\![0-9]{4}[-]+[0-9]{2}[-]+[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2},){1,}'

要点:

我想选择用户发送了与此正则表达式匹配的内容的记录

 '\\[cd(i|b)?(=[a-z0-9]+)?\\].+\\[/cd(i|b)?\\]' 

然后检查该帖子是否已使用正则表达式

收到至少两个ups(或喜欢)
'(\\|[0-9]+\\![0-9]{4}[-]+[0-9]{2}[-]+[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2},){2,}'

可以简单地分解:

a prefix pipe: |
a user id: [0-9]+
an exclamation mark: !
a datetime: [0-9]{4}[-]+[0-9]{2}[-]+[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}
and a sufix: ,
NOTE: {2,}  simply to check how many times the match occurs

请有人指出我正确的方向是错误的。

样本表数据:

Table A
ID    | POST
23  match found [cd=plain]6h+#gtyr[/cd]
24       match found [cd]65#%gte2!iu[/cd]
25       match found [cdi]*tre&y^g82u[/cdi]
26       no match found *tre&y^g82u
27       no match found rtyure99
28       match found [cdb]aha87ulchr[/cdb]

Table B
ID  |   POST_ID     |   UPPERS

4       24              |98!2018-02-10 22:43:03,
                    |35!2018-02-08 20:42:09,
                                            |3!2018-02-05 02:05:07,

5       26              |2!2018-02-10 22:43:03,
                    |30!2018-02-08 20:42:09,

6       25              |21!2018-02-10 22:43:03,

7       27              |23!2018-02-10 22:43:03,
                    |11!2018-02-08 20:42:09,

注意:表B中的POST_ID是引用表A的ID的外键

1 个答案:

答案 0 :(得分:0)

如果你不介意,我实际上会回答你实际问题背后的问题。我确信我们可以解决为什么正则表达式没有按预期工作,但它引出了一个问题:为什么要使用正则表达式来完成这么简单的任务?

人们首先使用数据库来存储与代码中出现的格式相同的内容。但如果你花一点时间以有意义的方式分解你的数据,你就可以从简陋的MySQL中释放出大量的力量。

考虑一下您希望此查询回答的问题:

  • 哪些符合特定条件的帖子已被提升?

正如您已经意识到的那样,这表示有两个表 - 一个用于存储有关帖子的信息,另一个用于存储有关谁将其提升的信息。为了使您的查询变得快速而简单,请考虑在where子句中显示哪些信息属性。

您想要某些标记所包含的帖子。为了提高搜索效率,请将标记标记放在自己的列中:

CREATE TABLE `posts` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `tag` enum('cd','cdi','cdb') DEFAULT NULL,
  `tag_value` varchar(11) DEFAULT NULL,
  `content` text NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

对于您在上面列出的数据,该表可能类似于:

+-----+------+-----------+-------------+
| id  | tag  | tag_value | content     |
+-----+------+-----------+-------------+
|  23 | cd   | plain     | 6h+#gtyr    |
|  24 | cd   | NULL      | 65#%gte2!iu |
|  25 | cdi  | NULL      | *tre&y^g82u |
|  26 | NULL | NULL      | *tre&y^g82u |
|  27 | NULL | NULL      | rtyure99    |
|  28 | cdb  | NULL      | aha87ulchr  |
+-----+------+-----------+-------------+

将数据输入需要更多的工作(这是你创建INSERT时更好地应用你的正则表达式权力的地方),但现在你可以很容易地用它来做各种各样的事情。我在tag列中使用了ENUM,因为搜索速度非常快。如果你有大量的标签或者不知道它们将会是什么,你可以改用VARCHAR。

那么如何跟踪UPPERS?那部分变得非常简单。你需要的只是一个表,每当有人举起一些东西时就会有一行:

CREATE TABLE `uppers` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `user_id` int(11) DEFAULT NULL,
  `post_id` int(11) DEFAULT NULL,
  `time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

目前,当有人举起某些内容时,您必须找到相关记录,向其添加新数据,然后将其保存回来。现在你可以将记录打到表中。时间将自动设定;您需要插入的只有user_idpost_id。您的部分数据可能如下所示:

+----+---------+---------+---------------------+
| id | user_id | post_id | time                |
+----+---------+---------+---------------------+
|  2 |      98 |      24 | 2018-02-10 15:23:03 |
|  3 |      35 |      24 | 2018-02-10 15:23:23 |
|  4 |      27 |      24 | 2018-02-10 15:23:43 |
|  5 |       2 |      26 | 2018-02-10 15:24:16 |
|  6 |      30 |      26 | 2018-02-10 15:24:28 |
+----+---------+---------+---------------------+

现在,您可以利用MySQL引擎的强大功能来捕获所需的所有信息:

所有包含所需标签的帖子:

SELECT * FROM posts where tag IN ('cd', 'cdi', 'cdb')

所有帖子都带有所需的标签,至少有一个:

SELECT posts.*, uppers.user_id, uppers.time
    FROM posts
    INNER JOIN uppers ON posts.id = uppers.post_id
    WHERE tag IN ('cd', 'cdi', 'cdb')

这将为每个后上组合返回一行。 INNER JOIN表示它不会返回任何在uppers表中没有匹配的帖子。这可能是您正在寻找的,但如果您想通过帖子ID将这些组合在一起,您可以让MySQL为您分组:

SELECT posts.*, COUNT(uppers.user_id)
    FROM posts
    INNER JOIN uppers
    WHERE tag IN ('cd', 'cdi', 'cdb')
    GROUP BY posts.id

如果您想排除同一用户的重复上传,您只需为每个帖子轻松计算唯一的用户ID:

SELECT posts.*, COUNT(DISTINCT uppers.user_id)
    FROM posts
    INNER JOIN uppers
    WHERE tag IN ('cd', 'cdi', 'cdb')
    GROUP BY posts.id

您可以使用许多功能,例如COUNT()来处理组合在一起的数据。您可以使用MAX(uppers.time)来获取该帖子的最新时间,或者您可以使用GROUP_CONCAT()之类的函数将值放在一个长字符串中。

最底层的是,通过将数据分解为基本部分,您可以让MySQL(或任何其他关系数据库)更有效地工作,生活变得更加容易。