【问题标题】:Teradata: Parsing a string based on a delimiter, then returning distinct values found in parsed stringTeradata:基于分隔符解析字符串,然后返回在解析字符串中找到的不同值
【发布时间】:2020-01-25 21:29:15
【问题描述】:

我有一个现有的数据库,其中包含一个我们可以称为“PACKAGES”的列,其中的值连接成一个字符串,每一行还包含一个相应的“ACCOUNT_ID”值。

Row 1: ACCOUNT_ID = 123, PACKAGES = 'AAA BBB CCC '
Row 2: ACCOUNT_ID = 456, PACKAGES = ' DDD DDD AAA BBB CCC CCC EEE'
Row 3: ACCOUNT_ID = 789, PACKAGES = 'FFF ZZZ QQQ QQQ'

我需要生成代码,让我为每个帐户分隔 packages 字段,以便 1) 代码识别 SPACE 何时引导字符,如第 2 行中的字符,以及 2) 仅显示各个帐户的不同包,即使ACCOUNT_ID 字段在生成的答案集中没有区别。

ACCOUNT_ID | PACKAGES    
123        | AAA
123        | BBB
123        | CCC
456        | DDD
456        | AAA
456        | BBB
456        | CCC
456        | EEE
789        | FFF
789        | ZZZ
789        | QQQ

我尝试在下面网上找到的一些示例代码中使用REGEXP,但我不知道在哪里可以从我正在使用的数据库中输入表名,也不知道是否可以替换我的“PACKAGES”字段以及下面的任何代码来获得我需要的东西。

SELECT * FROM TABLE (

    REGEXP_SPLIT_TO_TABLE ('SMART PHONES','MOTOROLA&MICROSOFT&GOOGLE&APPLE','&','C')

    RETURNS (OUTKEY VARCHAR(10), TOKEN_NDX INTEGER, TOKEN VARCHAR(10))

) AS T1;

【问题讨论】:

    标签: sql teradata teradata-sql-assistant


    【解决方案1】:

    添加到@Andrew 的答案。

    将数据传递给表运算符的最简单方法是使用通用表表达式:

    WITH cte AS
     ( -- whatever you need to prepare your data
       SELECT * FROM your_table 
     )
    SELECT
      DISTINCT account_Id, package
    FROM TABLE (RegExp_Split_To_Table(cte.account_id,cte.packages, ' ','c')
         RETURNS (account_Id INTEGER, tok_num INTEGER,package VARCHAR(100))) AS t
    

    但在您的情况下,不需要 RegEx,还有另一个 UDF 可以根据分隔符拆分字符串:

    WITH cte AS
     ( -- whatever you need to prepare your data
       SELECT * FROM your_table 
     )
    SELECT
      DISTINCT account_Id, package
    FROM TABLE (StrTok_Split_To_Table(cte.account_id,cte.packages, ' ')
         RETURNS (account_Id INTEGER, tok_num INTEGER,package VARCHAR(100))) AS t
    

    【讨论】:

    • strtok_split_to_Table 是否比 regexp_split_to_table 更好/更高效/更便宜/其他?
    • @Dnoeth 有什么方法可以实现类似但使用多字符分隔符?
    • @GalalOuda:RegExp_Slit_To_Table 应该能够处理这个
    • Regexp_Split_To_Table 超出缓冲区大小限制
    【解决方案2】:

    regexp_split_to_table 的语法总是让我抓狂。

    select
    *
    from
    table (regexp_split_to_table(<your db.table>.account_id,<your db.table>.packages, ' ','c')
    returns   (account_Id integer, tok_num integer,package varchar(100))) as t
    

    这会给你:

    account_Id  tok_num package
        123     1       AAA
        123     2       BBB
        123     3       CCC
    

    要仅获取不同的值,您可以运行:

    select
     distinct account_id,package
    from
    table (regexp_split_to_table(<your db.table>.account_id,<your db.table>.packages, ' ','c')
    returns   (account_Id integer, tok_num integer,package varchar(100))) as t
    order by account_id,package
    

    编辑:

    在您对超出长度的评论之后,我做了一点挖掘。 STRTOK_SPLIT_TO_STRING 似乎能够处理更长的字符串,包括比 REGEXP_SPLIT_TO_STRING 更长的字符串(不要问我为什么......)。所以,从@DNoeth 挖一点,这里有一些东西可以尝试:

    with cte as (
    select account_id,
    cast(packages as clob)
    from your_table)
    SELECT
      DISTINCT account_Id, package
    FROM TABLE (StrTok_Split_To_Table(cte.account_id,cte.packages, ' ')
         RETURNS (account_Id INTEGER, tok_num INTEGER,package VARCHAR(100))) AS t
    

    我拼凑了一个巨大的 (60k) 字符串并用它测试了这个逻辑,它对我有用。请注意,需要强制转换为 clob,否则会出现相同的错误。

    【讨论】:

    • 嗨,安德鲁。我使用了您提供的第一条语句,将“your db”替换为我的数据库名称,将“table”替换为我的表名,以及实际的列名。我还包括了一个SELECT TOP 1 * FROM TABLE 来缩短查询。我收到SELECT Failed. [9134] Input exceeds the buffer size limit 错误。有没有办法逃避这个错误?感谢您的所有帮助!
    • 我认为这意味着您的输入字符串(第二个参数,我的代码中的 table.packages)超过了函数支持的最大长度。该列是如何定义的?
    • 查看最后的编辑是否适合您。从@dnoeth 借了一点。
    猜你喜欢
    • 2021-01-20
    • 2016-06-27
    • 1970-01-01
    • 1970-01-01
    • 2018-06-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多