Reputation: 327
I have a table that looks like
ID | DATE | FIRST_NAME | H&P |
---|---|---|---|
12 | 2023-02-01 | JESSICA | 40 |
99 | 2023-02-03 | MINA | 98 |
12 | 2023-01-14 | JACK | 12 |
I've created another table containing these columns as columns by doing
SELECT ID, OBJECT_CONSTRUCT(*) as details
FROM MY_TABLE;
ID | DETAILS |
---|---|
12 | {"DATE":"2023-02-01", "FIRST_NAME":"JESSICA", "H&P":"40"} |
99 | {"DATE":"2023-02-03", "FIRST_NAME":"MINA", "H&P":"98"} |
12 | {"DATE":"2023-01-14", "FIRST_NAME":"JACK", "H&P":"12"} |
Is there a way to modify the DETAILS column when using OBJECT_CONSTRUCT() so that the KEYS of the json are lowercase but the VALUES stay the same as they appear, so I could get something like
ID | DETAILS |
---|---|
12 | {"date":"2023-02-01", "first_name":"JESSICA", "h&p":"40"} |
99 | {"date":"2023-02-03", "first_name":"MINA", "h&p":"98"} |
12 | {"date":"2023-01-14", "first_name":"JACK", "h&p":"12"} |
thanks! (I would like to do this without listing out the columns as my actual table has about 400 columns)
Upvotes: 4
Views: 958
Reputation: 5243
If you work with a tool like DBT, you could create a macro which calls OBJECT_CONSTRUCT()
with all of the columns listed out. All you'd have to do is to document the columns in your model's YAML file, and then you could grab them via model.columns
in the macro.
That is probably what would offer the best performance.
Upvotes: 0
Reputation: 5243
You can also do this with a very simple JavaScript UDF:
CREATE OR REPLACE FUNCTION lower_object_keys(
OBJ OBJECT
)
RETURNS OBJECT
LANGUAGE JAVASCRIPT
IMMUTABLE
AS
$$
return Object.fromEntries(
Object.entries(OBJ).map(
([k, v]) => [k.toLowerCase(), v]
)
);
$$;
And then you can easily do:
SELECT lower_object_keys(OBJECT_CONSTRUCT(*))
FROM ...
Upvotes: 0
Reputation: 175556
Keys could be listed explicitly as lower cased:
CREATE OR REPLACE TABLE MY_TABLE(ID INT, DATE DATE, FIRST_NAME TEXT, "H&P" INT)
AS
SELECT 12, '2023-02-01', 'JESSICA', 40 UNION
SELECT 99, '2023-02-03', 'MINA', 98 UNION
SELECT 12, '2023-01-14', 'JACK', 12;
SELECT ID, OBJECT_CONSTRUCT('date', DATE,
'fist_name', FIRST_NAME,
'h&p', "H&P") AS details
FROM MY_TABLE;
Output:
ID | DETAILS |
---|---|
12 | { "date": "2023-02-01", "fist_name": "JESSICA", "h&p": 40 } |
99 | { "date": "2023-02-03", "fist_name": "MINA", "h&p": 98 } |
12 | { "date": "2023-01-14", "fist_name": "JACK", "h&p": 12 } |
Using OBJECT constant syntax:
SELECT ID, {'date': DATE,
'fist_name': FIRST_NAME,
'h&p': "H&P"} AS details
FROM MY_TABLE;
EDIT:
Is there a way to do it without explicitly listing the columns?
Yes, one option requires flattening and building object second time which will reduce the performance:
WITH cte AS (
SELECT ID, OBJECT_CONSTRUCT(*) AS details
FROM MY_TABLE
)
SELECT ID, OBJECT_AGG(LOWER(f.KEY), f.VALUE) AS details
FROM cte
,LATERAL FLATTEN(INPUT => cte.details) AS f
GROUP BY ID, SEQ;
Output:
Upvotes: 5