Convert array of strings to array of integer [Snowflake] - snowflake-cloud-data-platform

I'm currently stuck with converting an array containing string values to an array of integers on snowflake. I've tried using a couple of functions like the SPLIT() and STRTOK_TO_ARRAY() on my column and casting the result as both a VARIANT and an INTEGER, and it appears I'm not getting anywhere with this.
So here's my table:
COL1
["1", "2", "3"]
and here's the result I want:
COL1
[1, 2, 3]
I've tried the following sql command on snowflake
select SPLIT(COL1, ',')::variant::integer;
but I doubt this would work because I'm getting this error instead
Failed to cast variant value ["1","2","3"] to FIXED
I know this looks basic but i've looked into various forums on this, and I can't really find a good approach

For sample input:
CREATE OR REPLACE TABLE tab(col1 VARIANT)
AS
SELECT '["1", "2", "3"]' UNION ALL
SELECT '["9", "7"]';
Query using FLATTEN and ARRAY_AGG:
SELECT COL1, ARRAY_AGG(TRY_CAST(f."VALUE"::TEXT AS INT)) AS COL1_Transformed
FROM tab
,TABLE(FLATTEN(INPUT=>TAB.COL1)) AS f
GROUP BY COL1, SEQ;
Output:

Related

Replacing elements in an array column in snowflake

I have sample data as follows;
team_id
mode
123
[1,2]
Here mode is an array.The goal is to replace the values in column mode by literal values, such as 1 stands for Ocean, and 2 stands for Air
Expected Output
team_id
mode
123
[Ocean,Air]
Present Approach
As an attempt, I tried to first flatten the data into multiple rows;
team_id
mode
123
1
123
2
Then we can define a new column assigning literal values to mode column using a case statement, followed by aggregating the values into an array to get desired output.
Can I get some help here to do the replacement directly in the array? Thanks in advance.
Using FLATTEN and ARRAY_AGG:
CREATE OR REPLACE TABLE tab(team_id INT, mode ARRAY) AS SELECT 123, [1,2];
SELECT TEAM_ID,
ARRAY_AGG(CASE f.value::TEXT
WHEN 1 THEN 'Ocean'
WHEN 2 THEN 'Air'
ELSE 'Unknown'
END) WITHIN GROUP(ORDER BY f.index) AS new_mode
FROM tab
,LATERAL FLATTEN(tab.mode) AS f
GROUP BY TEAM_ID;
Output:
TEAM_ID
NEW_MODE
123
[ "Ocean", "Air" ]
For an alternative solution with easy array manipulation. you could create a JS UDF:
create or replace function replace_vals_in_array(A variant)
returns variant
language javascript
as $$
dict = {1:'a', 2:'b', 3:'c', 4:'d'};
return A.map(x => dict[x]);
$$;
Then to update your table:
update arrs
set arr = replace_vals_in_array(arr);
Example setup:
create or replace temp table arrs as (
select 1 id, [1,2,3] arr
union all select 2, [2,4]
);
select *, replace_vals_in_array(arr)
from arrs;

How to replace string column with number 0 if the values in that column is null

Hope this is right place to ask question related to snowflake database..
I would like to know how to replace string column value with 0 if it is null.
so far, i tried nvl function, but that didn't work.
CREATE TABLE EMP(ENAME VARCHAR(10));
INSERT INTO EMP VALUES('JACK');
INSERT INTO EMP VALUES(null);
SELECT NVL(ENAME,0) FROM EMP1;
Error :Numeric value 'JACK' is not recognized
Any help would be appreciated.
Thanks,
Nawaz
SQL is strongly typed. The output type of NVL is being inferred to be an NUMBER, so the actual query looks something like
SELECT NVL(ENAME::NUMBER, 0) FROM EMP1;
You should decide what type your output should be. If you want strings, then you will need to pass NVL a string, like
SELECT NVL(ENAME, '0') FROM EMP1;
If you want integers, you will need to convert the strings to integers safely. For example, if you want non-integers to become NULL, then 0, then you can use
SELECT NVL(TRY_TO_INTEGER(ENAME), 0) FROM EMP1;

How to parse a table with a JSON array field in PostgreSQL into rows?

I have a table that contains a json array. Here is a sample of the contents of the field from:
SELECT json_array FROM table LIMIT 5;
Result:
[{"key1":"value1"}, {"key1":"value2"}, ..., {"key2":"value3"}]
[]
[]
[]{"key1":"value1"}
[]
How can I retrieve all the values and count how many of each value was found?
I am using PostgreSQL 9.5.14, and I have tried the solutions here Querying a JSON array of objects in Postgres
and the ones suggested to me by another generous stackoverflow user in my last question: How can I parse JSON arrays in postgresql?
I tried:
SELECT
value -> 'key1'
FROM
table,
json_array_elements(json_array);
which sadly does not work for me due to receiving the error: cannot call json_array_elements on a scalar
This error happens when using a query that returns more than one row or more than one column as a scalar subquery.
Another solution I tried was:
SELECT json_array as json, (json_array->0),
coalesce(
case
when (json_array->0) IS NULL then null
else (json_array->0->>'key1')
end,
'No value') AS "Value"
FROM table;
which only returned null values for the "Value"
Referencing Querying a JSON array of objects in Postgres I attempted to use this solution as well:
WITH json_test (col) AS (
values (json_arrays)
)
SELECT
y.x->'key1' "key1"
FROM json_test jt,
LATERAL (SELECT json_array_elements(jt.col) x) y;
But I would need to be able to fit all the elements of the json_arrays into json_test
So far I have only attempted to list all the values in the all json arrays, but my ideal end-result for the query resembles this:
Value | Amount
---------------
value1 | 48
value2 | 112
value3 | 93
value4 | 0
Yet again I am grateful for any help with this, thank you in advance.
step-by-step demo:db<>fiddle
SELECT
each.value,
COUNT(*)
FROM
data,
json_array_elements(json_array) elems, -- 1
json_each_text(elems) each -- 2
GROUP BY each.value -- 3
Expand array into one row for each array element
split the key/value pairs into two columns
group by the new value column/count

PSQL: Count number of wildcard values in JSONB array

My table has a jsonb column that stores JSON arrays of strings in this format:
["ItemA", "ItemB", "ItemC"]
I'm trying to filter the rows based on the number of certain items in the array, using a wildcard for a part of the name of the item.
From what I have read here on SO, I could use the jsonb_to_recordset function and then just query the data normally, but I can't put the pieces together.
How do I use the jsonb_to_recordset to accomplish this? It's asking for a column definition list, but how do I specify one for just a string array?
My hypothetical (but of course not valid) query would look something like this:
SELECT * FROM mytable, jsonb_to_recordset(mytable.jsonbdata) AS text[] WHERE mytable.jsonbdata LIKE 'Item%'
EDIT:
Maybe it could be done using something like this instead:
SELECT * FROM mytable WHERE jsonbdata ? 'Item%';
Use jsonb_array_elements():
select *
from
mytable t,
jsonb_array_elements_text(jsonbdata) arr(elem)
where elem like 'Item%';
jsonbdata | elem
-----------------------------+-------
["ItemA", "ItemB", "ItemC"] | ItemA
["ItemA", "ItemB", "ItemC"] | ItemB
["ItemA", "ItemB", "ItemC"] | ItemC
(3 rows)
Probably you'll want to select only distinct table rows:
select distinct t.*
from
mytable t,
jsonb_array_elements_text(jsonbdata) arr(elem)
where elem like 'Item%';

How to formulate an array literal of a composite type containing arrays?

I have a composite type like
CREATE TYPE example AS (id integer, some_stuff integer[]);
Thought I can use an array of this type as an argument of a function. The only problem is I couldn't find a way to build an array literal for that... If I try obtain it from PostgreSQL:
WITH elements AS (
SELECT (12, '{1,2}')::example AS e UNION
SELECT (3, '{3,1}')::example
)
SELECT array_agg(e) FROM elements;
I get the following:
{"(3,\"{3,1}\")","(12,\"{1,2}\")"}
But look:
SELECT E'{"(3,\"{3,1}\")","(12,\"{1,2}\")"}'::example[];
ERROR: malformed array literal: "{"(3,"{3,1}")","(12,"{1,2}")"}"
LINE 1: select E'{"(3,\"{3,1}\")","(12,\"{1,2}\")"}'::example[]
Is there a way to do this?
Try using ARRAY and ROW constructors:
Select array[row(3, array[3,1]), row(12, array[1,2])]::example[];
array
------------------------------------
{"(3,\"{3,1}\")","(12,\"{1,2}\")"}
(1 row)
If you want solution without using constructors, then use following example:
Select E'{"(3,\\"{3,1}\\")","(12,\\"{1,2}\\")"}'::example[];
example
------------------------------------
{"(3,\"{3,1}\")","(12,\"{1,2}\")"}
(1 row)
As you see main issue here is that you need to write \\", because this effectively means \" (using "escape" string syntax) that you saw as output of your first select.

Resources