Snowflake cloud data platform 雪花将属性值透视到对象数组中的列中

Snowflake cloud data platform 雪花将属性值透视到对象数组中的列中,snowflake-cloud-data-platform,Snowflake Cloud Data Platform,编辑:我给出了错误的示例数据。更新了一些详细信息,并将虚拟数据转换为经过消毒的实际数据 源系统:Freshdesk via Stitch 表结构: create or replace TABLE TICKETS ( CC_EMAILS VARIANT, COMPANY VARIANT, COMPANY_ID NUMBER(38,0), CREATED_AT TIMESTAMP_TZ(9), CUSTOM_FIELDS VARIANT, DUE_BY

编辑:我给出了错误的示例数据。更新了一些详细信息,并将虚拟数据转换为经过消毒的实际数据

源系统:Freshdesk via Stitch

表结构:

create or replace TABLE TICKETS (
    CC_EMAILS VARIANT,
    COMPANY VARIANT,
    COMPANY_ID NUMBER(38,0),
    CREATED_AT TIMESTAMP_TZ(9),
    CUSTOM_FIELDS VARIANT,
    DUE_BY TIMESTAMP_TZ(9),
    FR_DUE_BY TIMESTAMP_TZ(9),
    FR_ESCALATED BOOLEAN,
    FWD_EMAILS VARIANT,
    ID NUMBER(38,0) NOT NULL,
    IS_ESCALATED BOOLEAN,
    PRIORITY FLOAT,
    REPLY_CC_EMAILS VARIANT,
    REQUESTER VARIANT,
    REQUESTER_ID NUMBER(38,0),
    RESPONDER_ID NUMBER(38,0),
    SOURCE FLOAT,
    SPAM BOOLEAN,
    STATS VARIANT,
    STATUS FLOAT,
    SUBJECT VARCHAR(16777216),
    TAGS VARIANT,
    TICKET_CC_EMAILS VARIANT,
    TYPE VARCHAR(16777216),
    UPDATED_AT TIMESTAMP_TZ(9),
    _SDC_BATCHED_AT TIMESTAMP_TZ(9),
    _SDC_EXTRACTED_AT TIMESTAMP_TZ(9),
    _SDC_RECEIVED_AT TIMESTAMP_TZ(9),
    _SDC_SEQUENCE NUMBER(38,0),
    _SDC_TABLE_VERSION NUMBER(38,0),
    EMAIL_CONFIG_ID NUMBER(38,0),
    TO_EMAILS VARIANT,
    PRODUCT_ID NUMBER(38,0),
    GROUP_ID NUMBER(38,0),
    ASSOCIATION_TYPE NUMBER(38,0),
    ASSOCIATED_TICKETS_COUNT NUMBER(38,0),
    DELETED BOOLEAN,
    primary key (ID)
);
注意变量字段、自定义字段。它在api和snowflake之间经历了一次不幸的转换。结果字段包含3个或更多对象的数组,每个对象都是自定义字段。我无法更改数据格式。示例:

# values could be null
[
  {
    "name": "cf_request",
    "value": "none"
  },
  {
    "name": "cf_related_with",
    "value": "none"
  },
  {
    "name": "cf_question",
    "value": "none"
  }
]

# or values could have a combination of null and non-null values
[
  {
    "name": "cf_request",
    "value": "none"
  },
  {
    "name": "cf_related_with",
    "value": "none"
  },
  {
    "name": "cf_question",
    "value": "concern"
  }
]

# or they could all have non-null values
[
  {
    "name": "cf_request",
    "value": "issue with timer"
  },
  {
    "name": "cf_related_with",
    "value": "timer stopped"
  },
  {
    "name": "cf_question",
    "value": "technical problem"
  }
]
我基本上希望将这些字段集中到select查询中,其中name属性的值成为列标题。使输出类似于以下内容:

+----+------------------+-----------------+-------------------+-----------------------------+
| id |    cf_request    | cf_related_with |    cf_question    |      all_other_fields       |
+----+------------------+-----------------+-------------------+-----------------------------+
|  5 | issue with timer | timer stopped   | technical problem | more data about this ticket |
|  6 | hq               | laptop issues   | some value        | more data                   |
|  7 | a thing          | about a thing   | about something   | more data                   |
+----+------------------+-----------------+-------------------+-----------------------------+
是否有一个函数可以搜索数组对象的值并返回具有限定值的对象?比如:

select
id,
get_object_where(name = 'category', value) as category,
get_object_where(name = 'subcategory', value) as category,
get_object_where(name = 'subsubcategory', value) as category
from my_data_table
不幸的是,PIVOT需要一个聚合函数,我尝试使用min和max,但只返回null值。如果有另一种不需要聚合的语法,那么与此方法类似的东西将非常有用

with arr as (
  select
  id, 
  cs.value:name col_name, 
  cs.value:value col_value
  from my_data_table,
    lateral flatten(input => custom_fields) cs
)
select 
*
from arr 
pivot(col_name for col_value in ('category', 'subcategory', 'subsubcategory')
as p (id, category, subcategory, subsubcategory);
可以使用以下方法,但它存在缺陷,因为每当添加新的自定义字段时,我都必须添加案例来说明阵列中的新位置

select
    id, 
    case 
      when custom_fields[0]:name = 'cf_request' then custom_fields[0]:value
      when custom_fields[1]:name = 'cf_request' then custom_fields[1]:value
      when custom_fields[2]:name = 'cf_request' then custom_fields[2]:value
      when custom_fields[2]:name = 'cf_request' then custom_fields[3]:value
      else null
    end cf_request,
    case 
      when custom_fields[0]:name = 'cf_related_with' then custom_fields[0]:value
      when custom_fields[1]:name = 'cf_related_with' then custom_fields[1]:value
      when custom_fields[2]:name = 'cf_related_with' then custom_fields[2]:value
      when custom_fields[2]:name = 'cf_related_with' then custom_fields[3]:value
      else null
    end cf_related_with,
    case 
      when custom_fields[0]:name = 'cf_question' then custom_fields[0]:value
      when custom_fields[1]:name = 'cf_question' then custom_fields[1]:value
      when custom_fields[2]:name = 'cf_question' then custom_fields[2]:value
      when custom_fields[2]:name = 'cf_question' then custom_fields[3]:value
      else null
    end cf_question,
    created_at
from my_db.my_schema.tickets;

我想你差点就成功了。您只需要在col_名称周围添加一个max或min。正如您所说的,它需要一个聚合函数,像max或min这样的函数在这里可以工作,因为它是在您拥有的名称/值对上聚合的。例如,如果您有2个子类别值,它将选择最小/最大值。从您的示例来看,这似乎不是问题,因此它将始终选择您想要的值。我可以通过以下查询复制您的场景:

WITH x AS (
    SELECT parse_json('[{"name": "category","value": "Bikes"},{"name": "subcategory","value": "Mountain Bikes"},{"name": "subsubcategory","value": "hardtail bikes"}]')::VARIANT as field_var
    ),
arr as (
  select
  seq,
  cs.value:name::varchar col_name, 
  cs.value:value::varchar col_value
  from x,
    lateral flatten(input => x.field_var) cs
)
select 
*
from arr
pivot(max(col_value) for col_name in ('category','subcategory','subsubcategory')) as p (seq, category, subcategory, subsubcategory);

我想你差点就成功了。您只需要在col_名称周围添加一个max或min。正如您所说的,它需要一个聚合函数,像max或min这样的函数在这里可以工作,因为它是在您拥有的名称/值对上聚合的。例如,如果您有2个子类别值,它将选择最小/最大值。从您的示例来看,这似乎不是问题,因此它将始终选择您想要的值。我可以通过以下查询复制您的场景:

WITH x AS (
    SELECT parse_json('[{"name": "category","value": "Bikes"},{"name": "subcategory","value": "Mountain Bikes"},{"name": "subsubcategory","value": "hardtail bikes"}]')::VARIANT as field_var
    ),
arr as (
  select
  seq,
  cs.value:name::varchar col_name, 
  cs.value:value::varchar col_value
  from x,
    lateral flatten(input => x.field_var) cs
)
select 
*
from arr
pivot(max(col_value) for col_name in ('category','subcategory','subsubcategory')) as p (seq, category, subcategory, subsubcategory);

我已经回答了下面的问题,但我确实想说,很遗憾,您的源数据不理解JSON名称/值对的概念。如果他们有,这将是一个直接的选择。不过,你似乎知道这一点-freshdesk API很好地代表了数据。我正在使用Stitch将数据复制到Snowflake中,我认为Stitch中的Freshdesk集成就是Singer.io tap Freshdesk将数据转换成这种格式。我编写了一个Snowflake存储过程来获取Snowflake中的动力学轴,检查我在下面的回答,但是我想评论一下,很遗憾您的源数据不理解JSON名称/值对的概念。如果他们有,这将是一个直接的选择。不过,你似乎知道这一点-freshdesk API很好地代表了数据。我正在使用Stitch将数据复制到Snowflake中,我认为Stitch中的Freshdesk集成就是Singer.io tap Freshdesk将数据转换为这种格式。我编写了一个Snowflake存储过程以获取Snowflake中的动力学轴,请检查,感谢您花时间回答此问题。我想通过创建一个示例来消除不必要的细节。我脱得太多了。我正在用实际数据和模式进行更新。对于给您带来的不便,我真的很抱歉。所以,您基本上需要一种动态的方式来完成我静态展示的内容。我认为您可以使用Javascript存储过程来实现这一点,在该存储过程中,您可以在JSON字段中获取所有可能的值,然后动态生成上面提到的SQL。我以前在Python中也做过类似的事情,但JS不是我的强项。非常确定这是可能的。我无法使用pivot使用min或max返回准确的结果。我将再次查看。我确信我可以找到动态生成查询的JS。只要我能得到pivot以返回正确的结果,我就会接受答案。@Stephenloyd您是否有在同一记录的同一列名称上有多个列值的情况?如果不是,则最小/最大值应起作用。如果您需要帮助,请随时发布您看到的内容。我在轴上翻转了col_值和col_名称。结果我得到了所有的空值。感谢您的帮助。感谢您抽出时间回答此问题。我想通过创建一个示例来消除不必要的细节。我脱得太多了。我正在用实际数据和模式进行更新。对于给您带来的不便,我真的很抱歉。所以,您基本上需要一种动态的方式来完成我静态展示的内容。我认为您可以使用Javascript存储过程来实现这一点,在该存储过程中,您可以在JSON字段中获取所有可能的值,然后动态生成上面提到的SQL。我以前在Python中也做过类似的事情,但JS不是
这不是我的强项。非常确定这是可能的。我无法使用pivot使用min或max返回准确的结果。我将再次查看。我确信我可以找到动态生成查询的JS。只要我能得到pivot以返回正确的结果,我就会接受答案。@Stephenloyd您是否有在同一记录的同一列名称上有多个列值的情况?如果不是,则最小/最大值应起作用。如果您需要帮助,请随时发布您看到的内容。我在轴上翻转了col_值和col_名称。结果我得到了所有的空值。谢谢你的帮助。