【问题标题】:Big Query String Manipulation using SubQuery使用 SubQuery 处理大查询字符串
【发布时间】:2022-01-24 14:33:21
【问题描述】:

我希望能在正确的方向上推动如何使用 GCP Big Query 实现这一点。

我的表中有一个字符串类型的列,在这个字符串中有一个重复的字符序列,我需要提取和处理每个字符。为了说明,假设列名是“仪器”。工具的可能值可能是:

'band=false;inst=basoon,inst=cello;inst=guitar;cases=false,permits=false'

在这种情况下,我需要提取“巴松管”、“大提琴”和“吉他”。

对不起,我或多或少是一个 SQL 新手。到目前为止,我有:

SELECT 
    bandId,
    REGEXP_EXTRACT(instruments, r'inst=.*?\;') AS INSTS
   
FROM `inventory.band.mytable`;

这会提取乐器子字符串 ('inst=basoon,inst=cello;inst=guitar;') 并给我一个输出列 'INSTS' 但现在我认为我需要将该列中的值拆分为逗号和做一些进一步的处理。这就是我卡住的地方,因为我看不到如何构建额外的查询或处理块。

如何参考 INSTS 以便进行后续处理?文档建议我应该使用 WITH 构建子查询,但我似乎什么也做不了。请哪位好心人帮我往正确的方向前进?

【问题讨论】:

    标签: sql google-cloud-platform google-bigquery


    【解决方案1】:

    BigQuery 有一个函数 SPLIT(),其作用与其他数据库中的 SPLIT_PART() 相同。

    假设您没有在逗号和分号之间交替来分隔您的 «key»=«value» 对,并且只使用分号, 首先,您将instruments 字符串拆分为包含inst= 的多个部分。为此,您可以使用与CROSS JOIN 连接的连续整数的内联表,这样您就可以在SPLIT(instruments,';',i) 中为i 增加整数值。您将获得格式为inst=% 的字符串,其中您需要等号后面的部分。您可以通过应用另一个 SPLIT() 来获得该部分,这一次使用等号作为分隔符,对于第二个拆分部分:

    WITH indata(bandid,instruments) AS (                                                                                                                                                         
    -- some input, don't use in real query ...
    -- I assume that you don't alternate between comma and semicolon for the delimiter, and stick to semicolon
      SELECT
      1,'band=false;inst=basoon;inst=cello;inst=guitar;cases=false;permits=false'
      UNION ALL
      SELECT
      2,'band=true;inst=drum;inst=cello;inst=bass;inst=flute;cases=false;permits=true'
      UNION ALL
      SELECT
      3,'band=false;inst=12string;inst=banjo;inst=triangle;inst=tuba;cases=false;permits=true'
    )
    -- real query starts here, replace following comma with "WITH" ...
    ,
    -- need a series of consecutive integers ...
    i(i) AS (
                SELECT 1 
      UNION ALL SELECT 2 
      UNION ALL SELECT 3 
      UNION ALL SELECT 4 
      UNION ALL SELECT 5 
      UNION ALL SELECT 6 
    )
    SELECT
      bandid
    , i
    , SPLIT(SPLIT(instruments,';',i),'=',2) AS instrument
    FROM indata CROSS JOIN i
    WHERE SPLIT(instruments,';',i) like 'inst=%'
    ORDER BY 1
    -- out  bandid | i | instrument 
    -- out --------+---+------------
    -- out       1 | 2 | basoon
    -- out       1 | 3 | cello
    -- out       1 | 4 | guitar
    -- out       2 | 2 | drum
    -- out       2 | 3 | cello
    -- out       2 | 4 | bass
    -- out       2 | 5 | flute
    -- out       3 | 2 | 12string
    -- out       3 | 3 | banjo
    -- out       3 | 4 | triangle
    -- out       3 | 5 | tuba
    

    【讨论】:

      【解决方案2】:

      考虑以下几个选项(这里只是为了演示不同的技术)

      选项 1

      select bandId, 
        ( select string_agg(split(kv, '=')[offset(1)])
          from unnest(split(instruments, ';')) kv
          where split(kv, '=')[offset(0)] = 'inst'
        ) as insts
      from `inventory.band.mytable`  
      

      选项 2(很明显,这是我的选择)

      select bandId, 
        array_to_string(regexp_extract_all(instruments, r'inst=([^;$]+)'), ',') instrs 
      from `inventory.band.mytable`           
      

      如果应用于您问题中的样本数据 - 两种情况下的输出都是

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-11-06
        • 1970-01-01
        • 1970-01-01
        • 2014-08-09
        • 1970-01-01
        相关资源
        最近更新 更多