【问题标题】:How to check if a string in one field exist in every element of a comma separated field如何检查一个字段中的字符串是否存在于逗号分隔字段的每个元素中
【发布时间】:2019-09-20 00:36:18
【问题描述】:

我有一个包含两个字段的表。第一个是name,类型为string。第二个包含一个或多个用逗号分隔的字符串(但它可以包含一个完全没有逗号的字符串)

我想构造一个查询来了解name 字段中的字符串 是否存在于names 字段中的每个 逗号分隔的字符串中。

示例 1:

---------------------------------------------------------
name          names
---------------------------------------------------------
myname        xmyname,myname,mynamey

所有逗号分隔的字符串都包含单词myname。所以查询不应该返回这一行。

但是,示例 2:

---------------------------------------------------------
name          names
---------------------------------------------------------
myname        x,myname,mynamey

应该退货。因为 x 不包含 myname。

条件是,如果name字段中的字符串在names字段的逗号分隔字符串的每个中都不存在,则返回该行。

这是不正确的,因为此查询在示例 2 中不会返回 true(其中包含 x,但不包含 myname)。

重要提示:

1) 逗号的数量没有限制。它可以是 0 个逗号或更多。如何处理?

2) 字符串是变量。字符串并不总是myname。每行在name 字段中包含一个不同的字符串。

【问题讨论】:

  • 您确实需要重新考虑您的数据库。将这些“名称”移动到单独的表中。如果你要做这种事情,你不应该只用一个列来操作。

标签: mysql sql regex


【解决方案1】:

试试这个正则表达式:

where not concat(names, ',') regexp replace('^([^,]*{n}[^,]*,)*$', '{n}', name)

db-fiddle demo

如何阅读模式:

内部模式[^,]*{n}[^,]*,表示

  • 任何非逗号字符 [^,] 重复任意次数(* 表示没有次数或多次)。
  • 后跟name 列的值({n} 是一个占位符,将使用replace() 函数替换为实际值)
  • 后跟任何非逗号字符 [^,] 重复任意次数
  • 后跟逗号

外部模式^({inner_pattern})*$表示

  • 字符串的开头 (^)
  • 后跟重复任意次数的内部模式
  • 后跟字符串结尾 ($)

为了完成这项工作,names 列 (concat(names, ',')) 中附加了一个逗号,因此字符串中的每个元素都以逗号结尾。

该模式将确保逗号分隔字符串中的任何元素都包含name 列的值。由于您想要相反的结果,我们使用where not ..

【讨论】:

  • 这似乎有效。您能否提供对查询的解释,以便我理解并接受答案。
  • 抱歉,还有一个问题。一切都很清楚,但是命令如何循环(遍历逗号分隔字符串中的每个元素)。该示例有效,但我不明白如何?例如,SQL 命令concat(names, ',') regexp replace('^([^,]*{n}[^,]*,)*$', '{n}', name)names 列和myname' in the name` 列中带有此字符串x,myname,mynamey,对我来说,正则表达式在中间字符串myname 中匹配,因此正则表达式将返回@ 987654343@?但就我而言,我希望它返回 false,因为 x 不包含 myname
  • x, 与内部模式不匹配,因为它不包含 myname。但是外部模式只“允许”在字符串的开始^ 和结束$ 之间重复内部模式。考虑一个简化的例子,我们希望字符串中只允许数字。 内部模式[0-9]外部模式^[0-9]*$x123 不会匹配整个模式,但 123 会匹配内部模式。那是^$,它们使模式变得严格。如果您删除它们,那么 x123 将匹配。
  • @user9371654 转到bottlecaps.de/rr/ui 并将Grammar ::= ( [^,]* 'myname' [^,]* ',' )* 粘贴到“编辑语法”选项卡中。然后点击“查看图表”并尝试使用这些规则构造x,myname,mynamey
【解决方案2】:

假设“myname”在两个逗号之间没有出现两次,您可以计算逗号和“myname”的数量:

where (length(names) - length(replace(names, ','))) >=
       length(names) - length(replace(names, 'myname', '12345'))

【讨论】:

  • 不幸的是,这并没有解决它。 1) myname 不是固定字符串。这是可以出现在name 字段中的变量字符串的示例。 2) 请注意有两个字段:namenames。我需要检查name 字段中的字符串出现在names 字段中逗号分隔字符串中的每个字符串中。 3) names 字段不以逗号结尾。 4) names 字段可以包含 0 个逗号(如果它包含单个字符串),但即使在这种情况下,name 字段中的字符串仍应出现在 names 字段中的单个字符串中。
  • @user9371654 请不要以这种方式将 CSV 存储在您的表格中。这将导致您不得不使用一些错误的 SQL 来完成查询。
  • @Tim Biegeleisen 谢谢。我知道。这就是现在的情况。
【解决方案3】:

这个答案一开始就给出了一个不正确的REGEXP 解决方案。但最好的办法是修复您的数据模型,使names 列中的每个名称实际上都位于单独的行中:

name     | names
myname   | xmyname
myname   | myname
myname   | mynamey
somename | x
somename | myname
somename | mynamey

现在我们可以做一个简单的聚合查询来回答你的问题:

SELECT name
FROM yourTable
GROUP BY name
HAVING COUNT(CASE WHEN names NOT LIKE CONCAT('%', name, '%') THEN 1 END) > 0;

Demo

【讨论】:

  • @正如我之前所说:这行不通。 '%myname%' 不是固定字符串。这只是一个可以在name 字段内的字符串示例。如何用select name的结果替换%myname%
  • 谢谢。而且我无法更改数据库 BTW。因此,此查询无需进行您提到的修复即可工作。我知道这不是在文本字段中用逗号分隔字符串的理想格式。但这就是现在的样子,我无法改变它。
  • 你需要一些非常强大的正则表达式支持来做你想做的事情,从我读到的内容来看,甚至 MySQL 8+ 也可能达不到要求。我投票赞成现在咬紧牙关改变你的设计。
  • 我仍然认为您的查询不会捕获name 仅出现在一个但不是所有逗号分隔字符串中的情况。可能代替> 0 我应该使用= the number of comma separated strings
  • 不,你误读了我的回答。我们按name 聚合,并记录每次names 包含name 的次数。因此,断言计数大于零符合您的标准。我在答案中添加了演示链接。
【解决方案4】:

您可以使用以下 SQL 查询来解决此问题

SELECT 
name, names
FROM 
`tablename` 
WHERE 
(LENGTH(names) - LENGTH(REPLACE(names, ',', '')) + 1) 
=  
ROUND (   
  (
        LENGTH(names)
        - LENGTH( REPLACE ( names, name, "") ) 
  )/ LENGTH(name)       
);

说明:-

这会告诉你有多少个单词用,分隔

(LENGTH(names) - LENGTH(REPLACE(names, ',', '')) + 1) - 

以下是匹配每行中的name 并返回找到的次数

 ROUND (   
    (
        LENGTH(names)
        - LENGTH( REPLACE ( names, name, "") ) 
    ) / LENGTH(name)        
)

DEMO

【讨论】:

    猜你喜欢
    • 2019-08-01
    • 2021-09-15
    • 2014-05-06
    • 2011-11-30
    • 2021-07-24
    • 2016-04-24
    • 1970-01-01
    • 1970-01-01
    • 2021-11-06
    相关资源
    最近更新 更多