试图从 Json 对象中排除特定列的并发症为什么要在 snowflake 上编写 SQL 查询

Complications trying to exclude a specific column from a Json object why writing an SQL query on snowflake

我是 Snowflake 的新手,我正在尝试编写一个 SQL 查询来创建一个 JSON 对象,同时从输出中排除特定列

table: 莱克斯

id Amount status
001 200 accept
001 100 accept
002 200 accept
002 100 accept
003 200 accept

到目前为止我的代码

With wt as (
    Select *
    FROM lex
),
-------Convert to JSON------
wt_json as (
    select id,
            ARRAY_AGG(object_construct_keep_null(*)) withdrawals
    from wt
    Group by id
)
select *  from wt_json

这会产生类似于此的输出

id withdrawals
01 [{id: 01, amount :200, status: accept},{id: 01, amount :100,status: accept}]
02 [{id: 02, amount :200, status: accept},{id: 02, amount :100,status: accept}]
03 [{id: 03, amount :200, status: accept}]

但是,我试图排除 JSON 对象中的 ID。

我想要达到的目标

id withdrawals
01 [{ amount :200, status: accept},{ amount :100,status: accept}]
02 [{ amount :200, status: accept},{ amount :100,status: accept}]
03 [{ amount :200, status: accept}]

使用OBJECT_DELETE

Returns an object containing the contents of the input (i.e.source) object with one or more keys removed.

With wt as (
    Select *
    FROM  lex
 ),
-------Convert to JSON------
wt_json as (
   select id,
       ARRAY_AGG(OBJECT_DELETE(object_construct_keep_null(*), 'id')) withdrawals
   from wt
   Group by id
)
select *  from wt_json

您正在 object_construct_keep_null 函数中使用 *。这意味着该对象是从所有可用列构造的。如果您不想要这个,那么请以 'key', value 的形式指定您想要的每一列。您可以单独包含“id”列来实现您想要的:

WITH src AS (
    SELECT '01' AS "id", 200 AS "amount", 'accept' AS "status"
    UNION ALL 
    SELECT '01' AS "id", 100 AS "amount", 'accept' AS "status"
    UNION ALL 
    SELECT '02' AS "id", 200 AS "amount", 'accept' AS "status"
    UNION ALL 
    SELECT '02' AS "id", 100 AS "amount", 'accept' AS "status"
    UNION ALL 
    SELECT '03' AS "id", 200 AS "amount", 'accept' AS "status"
)
SELECT 
      "id"
    ,  array_agg(
          object_construct_keep_null(
                'amount', "amount", 
                'status', "status"
          )
       ) AS "withdrawals"
FROM src
GROUP BY "id"

结果:

id     withdrawals
---------------------------------------------------------------------------------------------------
01  [  {    "amount": 200,    "status": "accept"  },  {    "amount": 100,    "status": "accept"  }]
02  [  {    "amount": 200,    "status": "accept"  },  {    "amount": 100,    "status": "accept"  }]
03  [  {    "amount": 200,    "status": "accept"  }]

所以 OBJECT_DELETE 的问题是 id 必须与密钥大小写相同,因为 JSON 区分大小写,而 SQL 不区分大小写,因此默认情况下,它全部变为大写,因此在我下面的代码中,我允许 id 为 non-qouted,对于 OBJECT_DELETE 命令,它实际上是 'ID'

因此:

WITH wt AS (
    SELECT * FROM VALUES
        ('001', 200, 'accept'),
        ('001', 100, 'accept'),
        ('002', 200, 'accept'),
        ('002', 100, 'accept'),
        ('003', 200, 'accept')
        v(id, amount, status)
)
SELECT w.id,
    ARRAY_AGG(object_construct_keep_null(*)) AS org_withdrawals,
    ARRAY_AGG(object_delete(object_construct_keep_null(*),'ID')) AS del_withdrawals,
    ARRAY_AGG(object_construct_keep_null('amount', w.amount, 'status', w.status)) AS add_withdrawals
FROM wt as w
GROUP BY 1;
ID ORG_WITHDRAWALS DEL_WITHDRAWALS ADD_WITHDRAWALS
001 [ { "AMOUNT": 200, "ID": "001", "STATUS": "accept" }, { "AMOUNT": 100, "ID": "001", "STATUS": "accept" } ] [ { "AMOUNT": 200, "STATUS": "accept" }, { "AMOUNT": 100, "STATUS": "accept" } ] [ { "amount": 200, "status": "accept" }, { "amount": 100, "status": "accept" } ]
003 [ { "AMOUNT": 200, "ID": "003", "STATUS": "accept" } ] [ { "AMOUNT": 200, "STATUS": "accept" } ] [ { "amount": 200, "status": "accept" } ]
002 [ { "AMOUNT": 200, "ID": "002", "STATUS": "accept" }, { "AMOUNT": 100, "ID": "002", "STATUS": "accept" } ] [ { "AMOUNT": 200, "STATUS": "accept" }, { "AMOUNT": 100, "STATUS": "accept" } ] [ { "amount": 200, "status": "accept" }, { "amount": 100, "status": "accept" } ]

如果你想控制你的输出对象的大小写,我会去 OBJECT_CONSTRUST 方向,因为你有独立的控制权。但是,如果您担心 table 会改变形状,或者有很多列,* - ID 方法可能是最简单的方法,尽管性能较低。