将文本拆分为具有只读权限的表行

时间:2017-04-14 20:54:35

标签: sql string oracle parsing

我是数据库的只读用户,他遇到以下问题:

情境:

公司的呼叫中心员工代表我们的客户通过我们的数据库向我提交门票。呼叫中心在其消息中包含完整长度的字母数字批号,以便我进行故障排除。根据故障单的更新次数,一个故障单可能有多条消息,每个消息都包含在消息中的零个或多个字母数字批号。我可以使用Oracle SQL和SQL工具访问所有这些消息。

如何仅提取批号以制作所有给定批号的单列表?

示例数据:

-- Accessing Ticket 1234 --
SELECT *
FROM communications_detail
WHERE ticket_num = 1234;


-- Results --
TICKET_NUM | MESSAGE_NUM | MESSAGE
------------------------------------------------------------------------------
      1234 |           1 | A customer recently purchased some products with
           |             | a lot number of vwxyz12345 and wants to know if
           |             | they have been recalled.
------------------------------------------------------------------------------
      1234 |           2 | Same customer found lots vwxyz23456 and zyxwv12345
           |             | in their storage as well and would like those checked.
------------------------------------------------------------------------------
      1234 |           3 | These lots have not been recalled. Please inform
           |             | the client.

SO-远:

我可以使用以下代码隔离常量字符串的批号,但它会被放入标准输出而不是表格格式。

DECLARE
   msg VARCHAR2(200) := 'Same customer found lots xyz23456 and zyx12345 in their storage as well and would like those checked.';
   cnt NUMBER        := regexp_count(msg, '[[:alnum:]]{10}');
BEGIN
   IF cnt > 0 THEN
      FOR i IN 1..cnt LOOP
         Dbms_Output.put_line(regexp_substr(msg, '[[:alnum:]]{10}', 1, i));
      END LOOP;
   END IF;
END;
/

目标:

  • 将结果输出到一个表中,该表本身可以用作较大查询语句中的表。
  • 以某种方式能够将此应用于与原始故障单关联的所有消息。

更新:将示例批号从8个字符更改为10个字符,以避免与邮件中的真实字词混淆。真实场景具有更长的代码和非常特定的格式,因此将使用更复杂的正则表达式。

更新2:尝试使用表变量而不是标准输出。它没有错误,但它没有填充我的查询标签...这可能只是用户错误...!

DECLARE
   TYPE lot_type IS TABLE OF VARCHAR2(10);
   lots lot_type := lot_type();
   msg VARCHAR2(200) := 'Same customer found lots xyz23456 and zyx12345 in their storage as well and would like those checked.';
   cnt NUMBER        := regexp_count(msg, '[[:alnum:]]{10}');
BEGIN
   IF cnt > 0 THEN
      FOR i IN 1..cnt LOOP
         lots.extend();
         lots(i) := regexp_substr(msg, '[[:alnum:]]{10}', 1, i);
      END LOOP;
   END IF;
END;
/

1 个答案:

答案 0 :(得分:1)

这是一种与您提供的LOT掩码匹配的正则表达式格式:'[a-z]{3}[0-9]{5}'。使用这样的东西可以帮助你避免在你的问题中提到的误报。

现在这里是一个只读的纯SQL解决方案。

with cte as ( 
       select 'Same customer found lots xyz23456 and zyx12345 in their storage as well and would like those checked.' msg
       from dual)
select regexp_substr(msg, '[a-z]{3}[0-9]{5}', 1, level) as lotno
from cte
connect by level <= regexp_count(msg, '[a-z]{3}[0-9]{5}')
;

我正在使用WITH子句来生成数据。重要的是使用CONNECT BY运算符,它是Oracle的分层数据语法的一部分,但是这里从一行生成一个表。伪列LEVEL允许我们遍历字符串并选出正则表达式模式的不同出现。

这是输出:

SQL> r
  1  with cte as ( select 'Same customer found lots xyz23456 and zyx12345 in their storage as well and would like those checked.' msg from dual)
  2  select regexp_substr(msg, '[a-z]{3}[0-9]{5}', 1, level) as lotno
  3  from cte
  4  connect by level <= regexp_count(msg, '[a-z]{3}[0-9]{5}')
  5*

LOTNO
----------
xyz23456
zyx12345

SQL>