【问题标题】:MySQL string splitting on delimiters分隔符上的 MySQL 字符串拆分
【发布时间】:2021-06-04 19:01:48
【问题描述】:

基于https://stackoverflow.com/a/59666211/4250302,我创建了存储函数get_enum_item,以便将来处理ENUM()类型字段中的可能值列表。

它工作得很好,但是......但如果分隔符本身是被拆分的字符串的一部分,我无法确定该怎么做。例如: (方括号是为了便于阅读)

mysql> set @q=",v1,',v2'" --empty string, "v1", "comma-v2";
mysql> select concat('[',get_enum_item(@q,',',0),']') as item;
+------+
| item |
+------+
| []   |
+------+

没关系

mysql> select concat('[',get_enum_item(@q,',',1),']') as item;
+------+
| item |
+------+
| [v1] |
+------+

也可以

mysql> select concat('[',get_enum_item(@q,',',2),']') as item;
+------+
| item |
+------+
| [']  |
+------+

这样不行

@q 包含 3 个逗号,其中前两个是真正的分隔符,而最后一个是第三个可能值的部分:"comma-v-two"。而且我不知道如何避免拆分功能的混淆。 “表单编辑器”模式下的 MySQL WorkBench 以某种方式解决了这个问题,但是我如何用 MySQL 的代码来解决这个问题呢?

好吧,我可以相信show_columns-like 查询以“硬编码”方式显示枚举:

select column_name,column_type
  from information_schema.columns
  where data_type='enum' and table_name='assemblies';
+--------------+------------------------------------------------------------------+
| COLUMN_NAME  | COLUMN_TYPE                                                      |
+--------------+------------------------------------------------------------------+
| AssetTagType | enum('','И/Н','Н/Н',',fgg')                                      |
| PCTagType    | enum('','И/Н','Н/Н')                                             |
| MonTagType   | enum('','И/Н','Н/Н')                                             |
| UPSTagType   | enum('','И/Н','Н/Н')                                             |
| OtherTagType | enum('','И/Н','Н/Н')                                             |
| state        | enum('в работе','на списание','списано')                         |
+--------------+------------------------------------------------------------------+

因此,我可以尝试使用',' 作为分隔符,但是如果“逗号-撇号”组合是可能值的一部分,这不会让我摆脱这种情况...... :-( 我唯一能想象的就是计算撇号,如果分隔逗号在偶数个 ' 之后,那么它就是分隔符,而如果它跟在奇数个 ' 之后,它就是价值的一部分。 除了愚蠢地扫描循环内的输入字符串之外,我无法发明任何东西。但也许还有其他一些建议可以正确拆分值?

请不要建议使用 PHP、Python、AWK 等。查询将从 Pascal (Lazarus, CodeTyphoon) 应用程序执行,调用外部处理器是非常不安全的。 作为最后的手段,我可​​以使用 Pascal 的代码处理column_type,但首先,我必须确保自己无法通过 MySQL 的功能解决该任务。

编辑:

select column_type from information_schema.columns
where column_name='assettagtype' and table_name='assemblies';

+------------------------------------------+
| COLUMN_TYPE                              |
+------------------------------------------+
| enum('','И/Н','Н/Н',''''',fgg','''')     |
+------------------------------------------+
1 row in set (0.00 sec)

第四场:'',fgg,第五场:'

【问题讨论】:

  • “请不要建议……”:是的,我会的。 SQL 不适用于此。
  • Simpel 列拆分是可能的,请参阅this,但这似乎更复杂。我确信它可以是 MySQL 中的一个,但应该这样做,这就是问题...
  • CSV 列表有 2 个特殊特征(格式选项) - 引号字符/子字符串和分隔字符/子字符串。它们具有相同的相对优先级,我无法理解 - 为什么您更喜欢引号而不是分隔符?如果引号和/或分隔符可能是值的子字符串,那么您必须简单地使用另一个子字符串。如果可能,则使用 CHAR(0) 作为分隔符,在这种情况下,您几乎总是不需要引号...
  • @Akina,我没有选择分隔符和边界。它们是类似“show_columns”的函数结果的一部分。请参阅我的问题的最后一个示例中的column_type 列。如果有任何方法可以将默认撇号和逗号更改为其他符号,我将非常感谢您的建议
  • @trincot,好吧...像这样爆炸字符串:'в работе','на списание','списано','',v3' 其中“撇号逗号”是列表中最新值的一部分。

标签: mysql enums


【解决方案1】:
set @q="'в работе','на списание','списано'";
WITH RECURSIVE cte as (
   select 1 as a union all
   select a+1 from cte where a<35
   )
select distinct  regexp_substr(@q,'''[^,]*''',a) as E from cte;
  • 35 的值太高会引发错误 ERROR 3686 (HY000): Index out of bounds in regular expression search.。 (我为此创建了一个bug
  • null 值应该被过滤掉...?

输出:

E
'в работе'
'на списание'
'списано'
null

编辑:通过一些努力,这也适用于更复杂的示例(不是每个“分阶段”示例!)

set @q="'в работе','на списание','списано',''',fgg'";
select @q;

WITH RECURSIVE cte as (
   select 1 as a union all
   select a+1 from cte where a<35
   )
select distinct regexp_substr(@q,'(''([^,]|[^''][^''])*'')',a) E  from cte;

输出:

E
'в работе'
'на списание'
'списано'
''',fgg'

【讨论】:

  • 据我所知,您使用 cte 作为“带计数器的循环”?好主意,但正则表达式有问题。它适用于简单的字符串(在您的示例中为一个)。但是在特殊字符的情况下它失败了:enum('','И/Н','Н/Н',''''',fgg','''') +---------+ | E | +---------+ | '' | | 'И/Н' | | 'Н/Н' | | ''''' | | '''' | | ''' | |空 | +---------+ 注意:没有'',fgg值的字段
  • 似乎除了对整个输入字符串进行愚蠢的顺序扫描之外别无他法......
  • 请提供(在您的问题中)一个“复杂”的例子!
  • enum('','И/Н','Н/Н',''''',fgg','''') 够复杂吗?嗯,这是“上演”的例子,但它显示了我关心的事情。
  • 就我个人而言,“分阶段”的例子并没有给我留下深刻的印象。这将是 ENUM 可能返回的有效吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-04
  • 1970-01-01
  • 2019-08-21
  • 1970-01-01
  • 1970-01-01
  • 2014-06-29
相关资源
最近更新 更多