【问题标题】:REGEXP_LIKE for character at any position within substring of 5 charactersREGEXP_LIKE 用于 5 个字符的子字符串中任意位置的字符
【发布时间】:2019-07-23 15:25:10
【问题描述】:

我有一个旧的 Access 查询,我正在尝试将其转换为 Oracle SQL。它的一部分查看一个字符串,该字符串可以包含一大堆文本,而字符串的另一部分是一系列五个字符,例如:

NNNNN

我要做的是找到这些字符中的任何一个Y 的位置,但仅限于在 5 个字符以内的特定格式时。例如,整个字符串可能是:

The quick brown fox jumps over the lazy dog NNNNN

我不想返回这个,因为这五个NNNNN 不包含Y

当前查询执行如下操作:

SELECT *
FROM foo
WHERE
(
bar LIKE '%Y____%' OR 
bar LIKE '%_Y___%' OR
bar LIKE '%__Y__%' OR 
bar LIKE '%___Y_%' OR
bar LIKE '%____Y%'
)

但是,我认为这可以通过一个 REGEXP_LIKE 语句更好地实现。我怎么能这样做?

【问题讨论】:

  • 我认为您需要提供更多示例数据以及对您正在寻找的格式的更好解释。你如何区分“5个字符”和“一大堆文字”?
  • 是的,我同意你的观点。我添加了更多上下文并阐明了预期结果。
  • 字符串中的所有内容都是“字符”——包括“空格”字符。您需要更好地解释您的要求。您的“澄清”没有澄清任何事情。在您的示例中,“quick”也是由空格包围的五个字母的子字符串,就像“NNNNN”一样 - 那么为什么要单独选择“NNNNN”?
  • @mathguy - 虽然仍然存在关于输入格式的问题,但 OP 没有使期望的结果更清晰是不正确的。您对发布的代码 sn-p 有错误的事实了解得太多了。
  • 为您节省更多麻烦的解决方案是将该列拆分为五个不同的列,分别代表每个是/否值的实际含义。

标签: sql oracle regexp-like


【解决方案1】:

你不能这样做吗?

where bar like '%Y%' and length(b) >= 5

这基本上是你的逻辑,不需要正则表达式。

如果您正在寻找 5 个字符,除了 1Y 之外都是 N,那么我希望您的 like 解决方案是:

where bar like '%YNNNN%' or bar like '%NYNNN%' or . . . 

一个简单的正则表达式版本对我来说并不明显。

一种接近的方法是:

where regexp_like(bar, '[YN]{5}') and    -- has a substring with 5 characters, all of which are Y and N
      not regexp_like(bar, 'Y[N]{0-3}Y'  -- has no substring with Y followed by 0-3 Ns and another Y

这可能会在其他文本中的某些单词上失败。但是,Y 后接 0 个或多个 N 后接 Y 在英语单词中是极不常见的。

当然,也有明显的:

where regexp_like(bar, 'YNNNN|NYNNN|NNYNN|NNNYN|NNNNY')

【讨论】:

  • @WSC - 您是否理解您在帖子中显示的查询,由OR 分隔的五个LIKE 条件,没有做您似乎想?它与 Gordon 的解决方案完全相同做同样的事情。您的问题陈述完全不清楚 - 您是否正在寻找五个连续 Y 字母的序列?或者还有什么?如果您不能用简单的英语清楚地说明问题,那么没有人可以提出好的解决方案(不要为此使用任何代码)。
  • @mathguy - 除了不必要的粗鲁和罗嗦(注意我的评论是如何传达了很多相同的内容,而这两者都不是),你错了。好的问题陈述应该包含有用的代码。
  • @MarkAdelsberger - 我相信你混淆了“好问题”(意味着整个帖子)和“好问题陈述” - 应该始终在编写第一行代码之前制定。
  • @mathguy - 你对我的精神状态的看法已被记录,但在你开始以文明的方式讨论情况之前,我已经完成了对你的 cmets 的处理。
  • @WSC - 这是戈登回答中的一个错误 - 我将编辑他的回答以更正它。 Oracle 中函数的名称是length,而不是len
【解决方案2】:

试试这个 WHERE 条款:

where regexp_like(regexp_substr(bar,'[YN]{5}'),'Y')    

下面的例子显示它只返回表“foo”中字符串(Ys 或 Ns)包含“Y”的那些记录。

select * from foo;
BAR
--------------------------------------------------
The quick brown fox jumps over the lazy dog YNNNN
The quick brown fox jumps over the lazy dog NYNNN
The quick brown fox jumps over the lazy dog NNYNN
The quick brown fox jumps over the lazy dog NNNYN
The quick brown fox jumps over the lazy dog NNNNY
The quick brown fox jumps over the lazy dog NNNNN
The quick brown fox jumps over the lazy dog NNNNN
The quick brown fox jumps over the lazy dog NNNNN
The quick brown fox jumps over the lazy dog NNNNN
The quick brown fox jumps over the lazy dog NNNNN

10 rows selected.
select * from foo where regexp_like(regexp_substr(bar,'[YN]{5}'),'Y');
BAR
--------------------------------------------------
The quick brown fox jumps over the lazy dog YNNNN
The quick brown fox jumps over the lazy dog NYNNN
The quick brown fox jumps over the lazy dog NNYNN
The quick brown fox jumps over the lazy dog NNNYN
The quick brown fox jumps over the lazy dog NNNNY

5 rows selected.

【讨论】:

  • 啊,这太棒了!我需要用我的实际数据进行测试,但这似乎正是我需要的。我没有想过首先使用 regexp_substr 将 regexp_like 标准缩小到五个 Y/N 部分。
【解决方案3】:

如其他地方所述,您发布的代码 sn-p 实际上并未将您要检查的 5 个字符归零。无论是因为它被错误地转录,还是因为代码从未按预期工作,或者其他什么,我不能说。但正如写的那样,它只是说字符串中的某处是一个被其他字符包围的 Y,所以总共至少有 5 个字符。

WHY does this match NNNNN

会满足该标准,因为字符串中的第三个字符是一个 Y,周围有一些其他字符,因此总数至少为 5。

如果您的意思是您总是查看 最后 5 个字符 - 如果 Ns 和 Ys 的 tre 块位于字符串的末尾 - 那么您的原始代码如果它从每个模式中删除尾随 % 将起作用。

在这种情况下,获取字符串的最后 5 个字符(使用当前 DBMS 提供的子字符串函数)并在该子字符串中查找任何 Y 可能会更容易。在这种情况下,如果您真的想使用正则表达式,您只需寻找匹配子字符串中任何位置的“Y”,但这可能有点矫枉过正。

一般来说,这似乎不太适合正则表达式解决方案 IMO

【讨论】:

  • 感谢您的全面回答。我直接从 Access 查询(使用*?Y???*)复制了逻辑,它似乎确实有效,但我想知道 Access 是否不将空格视为字符或其他东西。我会玩弄你和 Gordon 的答案,看看我能做些什么。
  • @WSC - 好吧,我不知道你所观察到的解释,但即使 Access 中的 ' ' 与 ? 不匹配(我 99% 确定无论如何都不是这样),它仍然可以匹配任何包含 Y 的 5 个字母单词的字符串......无论如何,祝你好运
【解决方案4】:

用户要求所有相似字符连续出现 5 次,其中一个替换 Y 而不仅仅是 N。这是解决方案之一:

select * from foo where
regexp_like(bar,'%Y(A{4}|B{4}|C(4)....Z{4}%)') or
regexp_like(bar,'%(A{4}|B{4}|C(4)....Z{4})Y%') or
regexp_like(bar,'%(A{1}|B{1}|C(1)....Z{1})Y(A{3}|B{3}|C{3)....Z{3})%') or
regexp_like(bar,'%(A{2}|B{2}|C(2)....Z{2})Y(A{2}|B{2}|C{2}....Z{2})%') or
regexp_like(bar,'%(A{3}|B{3}|C(3)....Z{3})Y(A{1}|B{1}|C{1}....Z{1})%');

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-10-06
    • 2016-12-24
    • 1970-01-01
    • 1970-01-01
    • 2012-05-21
    • 2015-03-30
    • 1970-01-01
    相关资源
    最近更新 更多