mysql - 从以某些字符为界的 MySQL 列中提取多个文本实例

标签 mysql sql

我想从 MySQL 列中提取某些片段,这些片段以某种独特的方式界定。这是一个例子:

我有下表 (TableA):

id | column_a
---+---------
1  | There is a user [u?u=990] and another [u?u=5458855].
2  | And here is just one user [u?u=9390].
3  | And here is nothing.

我想得到这个:

id | result_a
---+---------
1  | 990
1  | 5458855
2  | 9390

目前我有这个问题:

SELECT id,SUBSTRING_INDEX(SUBSTRING_INDEX(column_a, '[u?u=', -1), ']', 1) AS result_a FROM TableA

但这给了我:

id | result_a
---+---------
1  | 5458855
2  | 9390

我怎样才能改进这个查询?

谢谢!

最佳答案

出现此问题是因为您的架构违反了 1NF

规范化模式将包含另一个表(看起来很像您要获得的结果,可能带有一个额外的“位置”列,指示从原始源中的位置预示的值),以及 column_a 中的值在您现有的表格中将不会包含您之后的数字,而是某种占位符。

当然,这就是(从某种意义上说)您要构建的……

SQL 确实不太适合从单个源行中提取多个结果:在 MySQL 中出现的唯一方法是通过 JOIN 。例如,可以尝试从每一行中获取两个实例——

SELECT id, SUBSTRING_INDEX(
             SUBSTRING_INDEX(column_a, '[u?u=', -1 - n.v)
           , ']', 1) AS result_a
FROM   TableA JOIN (
         SELECT 0 v
       UNION ALL
         SELECT 1
       ) n

当然,这种方法有一些问题:

  1. 它为 every 行返回两条记录,这是不正确的——这可以通过仅过滤那些找到的文本与所需模式匹配的记录来解决:

    WHERE RIGHT(column_a, 5+CHAR_LENGTH(
            SUBSTRING_INDEX(column_a, '[u?u=', -1 - n.v)
          )) REGEXP '^\\[u\\?u=.*\\]'
    
  2. 它要求连接表一直计数到预期实例的最大数量,你说的可能多达 100 个——而不是显式地这样做,这对于这样的一个对象来说显然很麻烦大数,一个人可以连接多个表来实现乘法而不是 e.g.使用二进制(至 128,但如果需要,表 WHERE 中的 n 过滤器可以限制为一些较小的数字):

    SELECT id, SUBSTRING_INDEX(
                 SUBSTRING_INDEX(column_a, '[u?u=', -1 - n.v)
               , ']', 1) AS result_a
    FROM   TableA JOIN (
             SELECT b6.v | b5.v | b4.v | b3.v | b2.v | b1.v | b0.v AS v
             FROM   (
                      SELECT 0 v UNION ALL SELECT 1<<0
                    ) b0 JOIN (
                      SELECT 0 v UNION ALL SELECT 1<<1
                    ) b1 JOIN (
                      SELECT 0 v UNION ALL SELECT 1<<2
                    ) b2 JOIN (
                      SELECT 0 v UNION ALL SELECT 1<<3
                    ) b3 JOIN (
                      SELECT 0 v UNION ALL SELECT 1<<4
                    ) b4 JOIN (
                      SELECT 0 v UNION ALL SELECT 1<<5
                    ) b5 JOIN (
                      SELECT 0 v UNION ALL SELECT 1<<6
                    ) b6
           ) n
    WHERE  RIGHT(column_a, 5+CHAR_LENGTH(
             SUBSTRING_INDEX(column_a, '[u?u=', -1 - n.v)
           )) REGEXP '^\\[u\\?u=.*\\]'
    
  3. MySQL 的字符串函数不是特别高效,这种方法会很慢。

关于mysql - 从以某些字符为界的 MySQL 列中提取多个文本实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32400235/

相关文章:

MySQL查询不使用索引

mysql - 如何用 "file sorting"和 "using temporary"优化MySQL查询(需要10多秒)

php - 如何在 PHP 中按日期(今天、昨天、8 月 29 日、28 日等)对 SQL 中的 foreach 项目进行排序?

mysql - 将数据存储在一张大表中或每月创建新表

sql - 在oracle中找到列中最长行的长度

mysql - Sql,按组获取所有可能的最小值

php - 查阅图像目录或数据库来统计有多少个更正确吗?

php - PHP 中的 session (用户登录)

php - 如何通过 php 中的 mysql 查询逐行迭代

php - SQL/Laravel 构建查询