【问题标题】:Select if string contains substring only once选择字符串是否仅包含一次子字符串
【发布时间】:2019-05-25 22:15:40
【问题描述】:

我正在尝试制作一个报告,该报告在两个日期之间提取数据,并且字符串在具有文本数据类型的描述列中仅出现一次

我尝试使用“postgresql-select-if-string-contains”stackoverflow 问题中的解决方案,但它没有考虑字符串在描述块中出现的次数。

SELECT o.ownername, to_char(a.auditdate, 'MM/DD/YYYY') as dateday, 
o.additionalflags, 
o.emailaddress, o.id, a.description, a.username, 
CASE WHEN a.Action = 0 THEN 'ADD'
WHEN a.Action = 1 THEN 'EDIT'
WHEN a.Action = 2 THEN 'DELETE'
WHEN a.Action = 3 THEN 'MOVE'
WHEN a.Action = 4 THEN 'LOGIN'
WHEN a.Action = 5 THEN 'LOGOUT'
END AS Action
FROM owner o
INNER JOIN audittrail a ON o.id = a.linkid
/*
WHERE array_length(regexp_matches(description, '1\-Gets Email'), 1) = 1
*/
AND a.auditdate >= '$ASK DATE Enter the from date$' 
AND a.auditdate <= '$ASK DATE Enter the to date$'
ORDER BY o.ownername

我要筛选的列包含如下所示的数据:

(ID 2) &gt;&gt;&gt; LASTCHANGEDDATE: 2011-11-11 11:11:11.653868 ==&gt; 2018-12-23 14:24:28.694724, ADDITIONALFLAGS: *1-Atest|1-Gets Email|1-Gets Snail Mail|Adopter-|donor|driver|fosterer|homechecked|homechecker|member|V-Foster Home: short-term/emergency|* ==&gt; **1-Gets Email|1-Gets Snail Mail|Adopter-NCGSPR Dog|donor|driver|fosterer|homechecked|homechecker|member|V-Foster Home: short-term/|volunteer|,**

该列几乎是数据库中更改内容的描述日志。斜体字是过去的ADDITIONALFLAGS,粗体字是更改后的新的和当前的ADDITIONALFLAGS。我正在寻找“1-Gets Email”一次的描述行,因为我只关心那些已经改变的行,而不是在我查询的日期之前有“1-Gets Email”的描述行。

【问题讨论】:

  • 您的加入将失败。您的查询是否正在运行?样本数据和预期结果会有所帮助..

标签: database postgresql select count where-clause


【解决方案1】:

split_part() 可用于简单快速的解决方案:

...
WHERE  description ~ '1-Gets Email'
AND    split_part(description, '1-Gets Email', 3) = '';

这会将搜索模式视为分隔符。如果没有第二个分隔符,则没有第三部分 - 在这种情况下为空。
如果搜索模式可能出现在字符串的开头或结尾,我们可能会得到误报,但在您的情况下可以排除这种极端情况,因为值包含在自定义分隔符中。

如果表很大,您可以添加一个三元组索引来支持第一个 WHERE 子句 (description ~ 'pattern') 并使其大大更快。喜欢:

CREATE INDEX tbl_description_gin_trgm_idx ON tbl USING gin (description gin_trgm_ops);

见:

【讨论】:

  • "split_part(description, '1-Gets Email', 3) = ''" -- 我也是这么想的,但它错过了边缘情况,即第二个1-Gets Email 位于字符串的末尾或紧随其后的是另一个。 dbfiddle.uk/…
  • @stickybit:我确实提到了这一点 - 以及为什么我认为它不适用于手头的案例。
  • 既然你提到了,我明白了。一定是忽略了这一点,抱歉。
【解决方案2】:

有点老套,但应该可以:检查描述的长度减去您搜索的文本的长度是否等于您搜索的文本被替换为空字符串的描述的长度。

...
WHERE length(description) - length('1-Gets Email') = length(replace(description, '1-Gets Email', ''))
...

或者更通用的方法:检查找到的匹配 regexp_matches() 的数量,在本例中为 1。

...
WHERE (SELECT count(*)
              FROM regexp_matches(description, '1\-Gets Email', 'g')) = 1
...

【讨论】:

  • 我修复了内部连接的语法问题,我尝试使用您的第一个代码,但我会得到一些描述列,而行内没有“1-Gets Email”。我认为给出的第二个代码是正确的,但我得到了一个错误:AND 的参数不能返回一个集合 LINE 12: WHERE array_length(regexp_matches(description, '1\-Gets Emai... ^
  • @SamRichardson:嗯,以为它正在返回一个数组,但它没有。也忘记了g 标志。更正它,请参阅我的编辑,并在此处:dbfiddle.uk/…
  • 非常感谢它现在可以工作,但我发现有些情况下“1-Gets Email”出现一次但只出现在“==>”之前,这意味着人们会出现,但他们目前在他们的附加标签中不会有“1-获取电子邮件”。有没有办法在“==>”之后只看到“1-Gets Email”。我尝试用 WHERE a.description LIKE '%' || 替换 WHERE 行'==> 1-获取电子邮件' || '%',但什么也没有出现。
  • @SamRichardson:您可以将正则表达式扩展到 Postgres 可以理解的任何正则表达式(您的版本),包括环视。
猜你喜欢
  • 2013-02-05
  • 2021-12-05
  • 2011-11-09
  • 2013-05-18
  • 1970-01-01
  • 2021-12-20
  • 2023-04-09
  • 1970-01-01
  • 2014-06-25
相关资源
最近更新 更多