当前位置: 首页 > 面试题库 >

在MySQL中以特定模式提取子字符串

岳和泽
2023-03-14
问题内容

我有一个文本字段,看起来像:

option[A]sum[A]g3et[B]

我想获取[ ]没有重复的文本。获得的含义:

A
B

不可能有double like的情况[ [ ] ]

我知道这是在数据库中保存数据的可怕方法。我无法更改数据的保存方式。我只需要从此列中获得非常具体的信息(一次)。

我试着做:

SELECT substring_index(substring_index(sentence, '[', -1),']', 1)
FROM (SELECT 'THIS[A] IS A TEST' AS sentence) temp;

这给了我A,但对许多人来说是行不通的[]

我曾想过使用正则表达式,但是我不知道有多少个[ ]

我怎么做?


问题答案:

这不是工作,DB但有可能:

CREATE TABLE tab(id INT, col VARCHAR(100));           
INSERT INTO tab(id, col) 
VALUES (1, 'option[A]sum[A]g3et[B]'), (2, '[Cosi]sum[A]g3et[ZZZZ]');      

SELECT DISTINCT *
FROM (
  SELECT id, RIGHT(val, LENGTH(val) - LOCATE('[', val)) AS val
  FROM
  (
    SELECT id, SUBSTRING_INDEX(SUBSTRING_INDEX(t.col, ']', n.n), ']', -1) AS val
    FROM tab t 
    CROSS JOIN 
    (
     SELECT a.N + b.N * 10 + 1 n
       FROM 
      (SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) a
      ,(SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) b
    ) n
    WHERE n.n <= 1 + (LENGTH(t.col) - LENGTH(REPLACE(t.col, ']', '')))
  ) sub
) s
WHERE val <> ''
ORDER BY ID;

笔记:

根据col最大长度,您可能需要在CROSS JOIN部分中生成更多数字。现在最多可以有100个。

输出:

在此处输入图片说明

这个怎么运作:

  1. 生成编号表 CROSS JOIN
  2. 根据]定界符分割字符串
  3. RIGHT(val, LENGTH(val) - LOCATE('[', val))删除部分直到 [
  4. 筛选出空记录
  5. 仅获DISTINCT取值

最内层查询:

╔════╦══════════╗
║ id ║   val    ║
╠════╬══════════╣
║  1 ║ option[A ║
║  1 ║ sum[A    ║
║  1 ║ g3et[B   ║
║  1 ║          ║
╚════╩══════════╝

第二个子查询:

╔════╦═════╗
║ id ║ val ║
╠════╬═════╣
║  1 ║ A   ║
║  1 ║ A   ║
║  1 ║ B   ║
║  1 ║     ║
╚════╩═════╝

最外层的查询:

╔════╦═════╗
║ id ║ val ║
╠════╬═════╣
║  1 ║ A   ║
║  1 ║ B   ║
╚════╩═════╝

我需要每行查询的结果..不合并

因此添加简单:

WHERE n.n <= 1 + (LENGTH(t.col) - LENGTH(REPLACE(t.col, ']', '')))
  AND t.id = ?

编辑2:

请参阅http://sqlfiddle.com/#!9/8ee95/1,您的查询对我的数据有部分作用。我也将类型更改为longtext。

您想在MySQL中解析JSON。正如我在解析并在应用程序层中获取价值之前所说的那样。该答案仅用于演示/玩具目的,并且性能会很差。

如果您仍然坚持使用SQL解决方案:

SELECT id, val,s.n
FROM (
  SELECT id, RIGHT(val, LENGTH(val) - LOCATE('[', val)) AS val,n
  FROM
  (
    SELECT id, SUBSTRING_INDEX(SUBSTRING_INDEX(t.col, ']', n.n), ']', -1) AS val, n.n
    FROM (SELECT id, REPLACE(col, '[]','') as col FROM tab) t
    CROSS JOIN 
    (
     SELECT e.N * 10000 + d.N * 1000 + c.N * 100 + a.N + b.N * 10 + 1 n
       FROM 
      (SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) a
      ,(SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) b
      ,(SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) c
      ,(SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) d
      ,(SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) e

    ) n
    WHERE n.n <= 1 + (LENGTH(t.col) - LENGTH(REPLACE(t.col, ']', '')))
  ) sub
) s
WHERE val <> ''
GROUP BY id, val
HAVING n <> MAX(n)
ORDER BY id,n;
SqlFiddleDemo

输出:

╔═════╦═════════════╦════╗
║ id  ║    val      ║ n  ║
╠═════╬═════════════╬════╣
║  1  ║ CE31285LV4  ║  1 ║
║  1  ║ D32E        ║  3 ║
║  1  ║ GTX750      ║  5 ║
║  1  ║ M256S       ║  7 ║
║  1  ║ H2X1T       ║  9 ║
║  1  ║ FMLANE4U4   ║ 11 ║
╚═════╩═════════════╩════╝

编辑3:

在那里到底做了什么?你为什么需要

CROSS JOIN并且整个子查询仅是理货表格。就这些。如果MySQL具有产生数字序列的功能(如generate_series或预先填充的数字表),则不需要CROSS JOIN。

需要以下数字表SUBSTRING_INDEX:

SUBSTRING_INDEX(str,delim,count)

在出现定界符delim之前,从字符串str返回子字符串。如果count为正,则返回最后定界符左侧的所有内容(从左侧开始计数)。如果count为负,则返回最后定界符右边的所有内容(从右边开始计数)。搜索delim时,SUBSTRING_INDEX()执行区分大小写的匹配。



 类似资料:
  • 我有一个以下格式的Java字符串==ocid1。instancepool。oc1.iad。aaaaaaaa wq4bibigdvw6esvmbia4zhs7dkaposzkzxuvir2ajtfyciih45fa 我想提取第三个和第四个点之间的子串,即“iad”。实现这一点的最佳方式是什么?逻辑应该是通用的,并且应该适用于任何有四个点的字符串。

  • 问题内容: 请原谅我的熊猫新手问题,但我有一列美国城镇和州,例如下面所示的截短的版本(出于某些奇怪的原因,该列的名称称为“ Alabama [edit]”,该列与第一个列中的0-7城镇值): 每个州的城镇均在每个州名称之下,例如,费尔班克斯(列值9)是阿拉斯加州的一个城镇。 我想要做的是根据州名称拆分城镇名称,这样我就有两列“州”和“地区名称”,其中每个州名称与每个城镇名称相关联,如下所示: 。。

  • 我有一个以下格式的Java字符串==ocid1。instancepool。oc1.iad。aaaaaaaa wq4bibigdvw6esvmbia4zhs7dkaposzkzxuvir2ajtfyciih45fa 我想提取第三点和第四点之间的子字符串,即“iad”。实现这一点的最佳方法是什么?逻辑应该是通用的,并且应该适用于任何有四个点的字符串。

  • 我得到以下字符串: 我想从里面拿走食物和饮料。 我尝试了以下代码: 但它给人的感觉是,食物很刺激,喝了很多,离食物很近,三个和四个。

  • 问题内容: 我正在尝试从控制台(包括空格)读取整行,然后对其进行处理。使用bufio.ReadString,将换行符与输入一起读取,因此我想出了以下代码来修剪换行符: 有没有更惯用的方法来做到这一点?也就是说,是否已经有一个库在为您提取子字符串时负责处理结尾的空字节? (是的,我知道在go readline->string中已经有一种不用换行符就能读取行的方法,但是我正在寻找更多用于优雅的字符串操

  • 问题内容: 我有一个像下面这样的文字 [:de] 15岁的BB2女士在holzbauweise的rkische Gulet的眉毛,Annehmlichkeiten的游艇和Eleganz einer的专业游艇,durch的高品质的盲人眉毛,glichen Holzverare的时尚和15岁的女孩密西西比州杜尚卡宾/ WC。Salon and Deck sind ausgesprochen gro脽z