I am using this
select 'select '
|| (select listagg(distinct 'json_col:'||key::text||'::string'||' as '||key::text, ', ') from GAURAV.PUBLIC.jsondata, lateral flatten(input=>json_col, mode=>'OBJECT'))
|| ' from GAURAV.PUBLIC.jsondata'
but it can't pick keys dynamic
it shows me output like this
I have Multiple json data in a table
how to flatten it
If I have a table of json like:
('{"key_a":"a", "key_b":"b"}'),
('{"key_c":"a", "key_d":"b"}')
this SQL
select
'select ' || listagg(distinct 'json_col:'|| f.key::text || '::string as ' || f.key::text, ', ') || ' from GAURAV.PUBLIC.jsondata' as output
from jsondata as jd,
table(flatten(input=>jd.json_col, mode=>'OBJECT')) f
group by f.seq
gives:
OUTPUT
select json_col:key_d::string as key_d, json_col:key_c::string as key_c from GAURAV.PUBLIC.jsondata
select json_col:key_a::string as key_a, json_col:key_b::string as key_b from GAURAV.PUBLIC.jsondata
The major points are to loop across the table as a first order selection. And to group the LISTAGG via the SEQ of the flatten which gives a distinct value per row of input, thus if you have 100 input rows, you will get 100 different seq, thus able to keep them separated.
It can be written with that output line split apart also:
select
'select ' ||
listagg(distinct 'json_col:'|| f.key::text || '::string as ' || f.key::text, ', ') ||
' from GAURAV.PUBLIC.jsondata' as output
from jsondata as jd,
table(flatten(input=>jd.json_col, mode=>'OBJECT')) f
group by f.seq
Related
Can you please help on below requirement in snowflake. We need to pass external argument into the query and need to build query based on external argument values then get out put of query in tabular format.
Below is the javascript base UDTF we are trying to create but couldn't finish as we are new to javascript.
CREATE OR REPLACE FUNCTION GetV_Test(I_VendorName varchar(100),I_Department DOUBLE)
RETURNS TABLE(VendorName VARCHAR(100), Vendor VARCHAR(100))
LANGUAGE JAVASCRIPT
AS
$$
if ((I_VendorName != null || I_VendorName !='') && (I_Department == null || I_Department == 0))
{
SELECT ' ' AS VendorName, ' ' AS Vendor
UNION
SELECT distinct(Cast(Vendor as varchar(1000)) || ' ' || VendorName) as VendorName, Vendor
FROM vdrs WHERE VendorName LIKE '%'||I_VendorName||'%'
}
else if((I_VendorName == null || I_VendorName == ' ') && (I_Department != null || I_Department!=0))
{
SELECT ' ' AS VendorName, ' ' AS Vendor
UNION
SELECT distinct (Cast(Vendor as varchar(1000)) || ' ' || VendorName) as VendorName,Vendor
FROM vdrs WHERE department =I_Department order by Vendor
}
else
{
SELECT ' ' AS VendorName, ' ' AS Vendor
UNION
Select distinct (CAST(vdrs2.Vendor as varchar(1000)) || ' ' || vdrs2.VendorName) as VendorName,vdrs2.Vendor
from (SELECT (Cast(Vendor as varchar(1000)) || ' ' || VendorName) as VendorName,Vendor
FROM vdrs WHERE department =I_Department)as temp1
Inner join vdrs2 on vdrs2.Vendor=temp1.Vendor
and vdrs2.VendorName LIKE '%'||I_VendorName||'%'
order by Vendor
}
$$
;
You can not combine SQL and JavaScript like you do:
if () {
SQL statement
} else {
SQL statement
}
It's not possible to read from another table(s) with JavaScript UDTF. Please check the samples:
https://docs.snowflake.com/en/developer-guide/udf/javascript/udf-javascript-tabular-functions.html
As a workaround:
You may create a JavaScript Stored Procedure, run these SQL statements to fill a transient or temp table, and then query this table with another SQL.
You may try to combine these SQLs and create a SQL UDTF:
https://docs.snowflake.com/en/developer-guide/udf/sql/udf-sql-tabular-functions.html
I want to create a generic query that will allow me to create a view (from a table) and convert all Array columns into strings.
Something like:
CREATE OR REPLACE VIEW view_1 AS
SELECT *
for each column_name in columns
CASE WHEN pg_typeof(column_name) == TEXT[] THEN array_to_string(column_name)
ELSE column_name
FROM table_1;
I guess that I can do that with stored procedure but I'm looking for solution in pure SQL, if it can be to much complex.
Here is a query to do such conversion. You can then customize it to create the view and execute it.
SELECT
'CREATE OR REPLACE VIEW my_table_view AS SELECT ' || string_agg(
CASE
WHEN pg_catalog.format_type(pg_attribute.atttypid, pg_attribute.atttypmod) LIKE '%[]' THEN 'array_to_string(' || pg_attribute.attname || ', '','') AS ' || pg_attribute.attname
ELSE pg_attribute.attname
END, ', ' ORDER BY attnum ASC)
|| ' FROM ' || min(pg_class.relname) || ';'
FROM
pg_catalog.pg_attribute
INNER JOIN
pg_catalog.pg_class ON pg_class.oid = pg_attribute.attrelid
INNER JOIN
pg_catalog.pg_namespace ON pg_namespace.oid = pg_class.relnamespace
WHERE
pg_attribute.attnum > 0
AND NOT pg_attribute.attisdropped
AND pg_namespace.nspname = 'my_schema'
AND pg_class.relname = 'my_table'
; \gexec
Example:
create table tarr (id integer, t_arr1 text[], regtext text, t_arr2 text[], int_arr integer[]);
==>
SELECT id, array_to_string(t_arr1) AS t_arr1, regtext, array_to_string(t_arr2) AS t_arr2, int_arr FROM tarr;
I am trying to order a table alphabetically, ascending, with nulls last but am having problems.
The code below produces the following error:
ORDER BY items must appear in the select list if SELECT DISTINCT is specified.
select distinct
'item' = othertab..item,
'stockedFor' = tab..stocked_for
+ ', ' + tab..stockedFor2
+ ', '+ tab..stockedFor3
from tab
order by case when stockedFor is null then 1 else 0 end, stockedFor
How can I return stockedFor alphabetically and nulls last?
Just wrap it in another select statement:
select stockedFor
from (
select distinct
'stockedFor' = tab..stocked_for
+ ', ' + tab..stockedFor2
+ ', '+ tab..stockedFor3
from tab
) x
order by case when stockedFor is null then 1 else 0 end, stockedFor
Since you are removing duplicates, a workaround is to use GROUP BY to remove duplicates instead of DISTINCT. The question has changed but the method still applies if putting all columns in the SELECT in the GROUP BY.
For example:
select
'item' = othertab..item,
'stockedFor' = tab..stocked_for
+ ', ' + tab..stockedFor2
+ ', '+ tab..stockedFor3
from tab
GROUP BY othertab..item,
tab..stocked_for
+ ', ' + tab..stockedFor2
+ ', '+ tab..stockedFor3
order by case when stockedFor is null then 1 else 0 end, stockedFor
I'd like to put together only unique values in the concatenated string. My code is currently:
SELECT PITEM2.orderid,
(SELECT ISNULL(E.FIRSTNAME + ' ' + E.LASTNAME,' ') + ', ' AS [text()]
FROM F_PURCHASEITEM PITEM1
LEFT JOIN E__EMPLOYEE E ON e.EMPLOYEEID=PITEM1.APPROVED_BY
WHERE PITEM1.ORDERID = PITEM2.ORDERID
AND PITEM1.PISTATUS =
(SELECT POSTATUSID
FROM F_POSTATUS
WHERE POSTATUSNAME = 'Invoice Received') GROUP By ISNULL(E.FIRSTNAME + ' ' + E.LASTNAME,' ') + ', '
FOR XML PATH ('') ) [EmployeeNames]
FROM F_PURCHASEITEM PITEM2
WHERE ORDERID=305089 Group By PITEM2.orderid
This gives me the output I'd expect, but the cost of the query increased and execution plan shows the Distinct sort as 46.3%.
How can I decrease the cost for this distinct?
Try to pull first and last name from a database combine into one value, and then combine the results with a different server database. The problem being my database has first and last separate, the target database has first and last combine in one string. Basically trying to get a list from both databases matching on the full name.
select a.empid,
select (SELECT REPLACE(RTRIM(COALESCE(a.FNAM + ' ', '') +
COALESCE(a.LNAM, '')), ' ', ' '))name1,
a.Email
from [db]..[user].[table] a, [server].[db].[dbo].[tblUsers] t
where name1 = t.Name
Witht he above, it just says invalid column anme1, which makes sense because it is just a result set column name. How can I make this full name value from my DB and then match it with the full name value of column t.Name
select a.empid,
a.FNAM, a.LNAM, t.Name
from [db]..[user].[table] a
join [server].[db].[dbo].[tblUsers] t
on Replace(a.FNAM + a.LNAM, ' ', '')
= Replace(t.Name, ' ', '')