Snowflake - Invalid Identifier - snowflake-cloud-data-platform

Hi i am getting invalid identifier for “owner”while executing this query below,i have tried single/double quotes and tilda
in show roles i have comments with email address and i am trying to get owner and owner email address.
comments example - {RoleType:"Access",Workload:"RTR",Application:"Business Automation",AppName:"RTR",Contact:"sabfinw#gmail.com",Director:"sabrish133#gmail.com",Environment:"DEV",Owner:"sanjayd.980#gmail.com",VP:"sabrish"}
show roles;
select owner,split_part(b.data,':',2) as Owner_Email from (
select a.value::string as data from TABLE(RESULT_SCAN(LAST_QUERY_ID())),
lateral flatten(input=>split("comment",',')) a) b where b.data like '%Owner%';

You will need to select the value from the inner select
SELECT
owner,
split_part(b.data,':',2) as Owner_Email
FROM (
SELECT r.owner,
a.value::string as data
FROM TABLE(RESULT_SCAN(LAST_QUERY_ID())) r,
LATERAL FLATTEN(input=>split(r.comment, ',')) a
) b
WHERE b.data LIKE '%Owner%';
Or you can use the QUALIFY clause to filter in the same time like:
SELECT r.owner,
split_part(a.value::string, ':', 2) as Owner_Email
FROM TABLE(RESULT_SCAN(LAST_QUERY_ID())) r,
LATERAL FLATTEN(input=>split(r.comment, ',')) a
QUALIFY a.value::string LIKE '%Owner%'

Related

Difference between LATERAL FLATTEN(...) and TABLE(FLATTEN(...)) in Snowflake

What is the difference between the use of LATERAL FLATTEN(...) and TABLE(FLATTEN(...)) in Snowflake? I checked the documentation on FLATTEN, LATERAL and TABLE and cannot make heads or tails of a functional difference between the following queries.
select
id as account_id,
account_regions.value::string as region
from
salesforce.accounts,
lateral flatten(split(salesforce.accounts.regions, ', ')) account_regions
select
id as account_id,
account_regions.value::string as region
from
salesforce.accounts,
table(flatten(split(salesforce.accounts.regions, ', '))) account_regions
I'll say that in the presented queries there's no difference - as the lateral join is implicit by the dynamic creation of a table out of the results of operating within values coming out of a row.
The real need for the flatten keyword comes out of queries like this:
select *
from departments as d
, lateral (
select *
from employees as e
where e.department_id = d.department_id
) as iv2
order by employee_id;
-- https://docs.snowflake.com/en/sql-reference/constructs/join-lateral.html
Without the lateral keyword for this join, you get an Error: invalid identifier 'D.DEPARTMENT_ID'.

Lateral Flatten two columns with different array length in snowflake

i am new to snowflake and currently learning to use Lateral Flatten.
I currently have a dummy table which looks like this:
The data type used for "Customer_Number" & "Cities" is array.
I have managed to understand and apply the Flatten concept to explode the data using the following sql statement:
select c.customer_id, c.last_name, f.value as cust_num, f1.value as city
from customers as c,
lateral flatten(input => c.customer_number) f,
lateral flatten(input => c.cities) f1
where f.index = f1.index
order by customer_id;
The output shown is:
As we can clearly see from the dummy table, in row 4 customer_id 104 has 3 numbers and i would like to see all three of it in my output and if there is no matching index value in cities i would like to just see "Null" in "City".
My expected output is:
Is this possible to be done ?
The trick is to remove the second lateral, and use the index from the first to choose values from the second array:
select c.customer_id, c.last_name, f.value as cust_num, cites[f.index] as city
from customers as c,
lateral flatten(input => c.customer_number) f
order by customer_id;
As long as you can be sure the second record is going to be shorter, you can do:
select customer_id, last_name, list1_table.value::varchar as customer_number,
split(cities,',')[list1_table.index]::varchar as city
from customers, lateral flatten(input=>split(customer_number, ',')) list1_table;
Otherwise you'd have to do union between the 2 sets of records (a regular union will eliminate duplicates)
You may want to use a LEFT OUTER JOIN for this task, but need to create a rowset version of the cities first.
select c.customer_id, c.last_name, f.value as cust_num, f1.value as city
from customers as c
cross join lateral flatten(input => c.customer_number) f
left outer join (select * from customers, lateral flatten(input => cities)) f1
on f.index = f1.index
order by customer_id;

SELECT Value from array

There is an array #array = select username from usertable
and the parameter is passed to the other query
SELECT
*
FROM transactiontable TT
WHERE TT.name in (SELECT value FROM string_split(#array, ','))
What is the benifit of doing this?
Can't I just do SELECT * from transcationtbale TT WHERE TT.name in #array?
Also, what is SELECT value FROM expression?
Thanks
It seems that 'username' field in 'usertable' is a string like 'user1, user2, user3'. Is it right?
If it is not, then use such query:
SELECT * from transcationtbale TT WHERE TT.name in (select username from usertable)
STRING_SPLIT is used to separate string by specified separator. Please, read this description at MSDN.
Let me show an example:
SELECT * FROM STRING_SPLIT('Adam,Joseph,Jon',',')
But if you select from table, then use just:
SELECT UserName FROM UserTable
There is no benefit between them, it cannot be comparable, it is like compare apples and oranges.

listagg data to useable format?

This is my first time working with the LISTAGG function and I'm confused. I can select the data easily enough, but the characters of the USERS column all have spaces in between them, and when trying to copypaste it, no data from that column is copied. I've tried with two different IDEs. Am I doing something wrong?
Example:
select course_id, listagg(firstname, ', ') within group (order by course_id) as users
from (
select distinct u.firstname, u.lastname, u.student_id, cm.course_id
from course_users cu
join users u on u.pk1 = cu.users_pk1
join course_main cm on cm.pk1 = cu.crsmain_pk1
and cm.course_id like '2015SP%'
)
group by course_id;
Yields:
I had similar problem, it turned out that the problem was with encoding. I got this solved like this (change to another encoding if needed):
...listagg(convert(firstname, 'UTF8', 'AL16UTF16'), ', ')...
Your firstname column seems to be defined as nvarchar2:
with t as (
select '2015SP.BOS.PPB.556.A'as course_id,
cast('Alissa' as nvarchar2(10)) as firstname
from dual
union all select '2015SP.BOS.PPB.556.A'as course_id,
cast('Dorothea' as nvarchar2(10)) as firstname
from dual
)
select course_id, listagg(firstname, ', ')
within group (order by course_id) as users
from t
group by course_id;
COURSE_ID USERS
-------------------- ------------------------------
2015SP.BOS.PPB.556.A
... and I can't copy/paste the users values from SQL Developer either, but it displays with spaces, as you can see from SQL*Plus:
COURSE_ID USERS
-------------------- ------------------------------
2015SP.BOS.PPB.556.A A l i s s a, D o r o t h e a
As the documentation says, the listagg() function always returns varchar2 (or raw), so passing in an nvarchar2 value causes an implicit conversion which is throwing out your results.
If you're stuck with your column being of that data type, you could cast it to varchar2 inside the listagg call:
column users format a30
with t as (
select '2015SP.BOS.PPB.556.A'as course_id,
cast('Alissa' as nvarchar2(10)) as firstname
from dual
union all select '2015SP.BOS.PPB.556.A'as course_id,
cast('Dorothea' as nvarchar2(10)) as firstname
from dual
)
select course_id, listagg(cast(firstname as varchar2(10)), ', ')
within group (order by course_id) as users
from t
group by course_id;
COURSE_ID USERS
-------------------- ------------------------------
2015SP.BOS.PPB.556.A Alissa, Dorothea
But you probably don't really want it to be nvarchar2 at all.
Apparently it's a known (unresolved?) bug in 11. TO_CHAR() worked for me...
SELECT wiporderno, LISTAGG(TO_CHAR(medium), ',') WITHIN GROUP(ORDER BY wiporderno) AS jobclassification
...where medium was the problematic column/data type.

Need to return all columns from a table when using GROUP BY

I have a table let's say it has four columns
Id, Name, Cell_no, Cat_id.
I need to return all columns whose count of Cat_id is greater than 1.
The group should be done on Cell_no and Name.
What i have done so far..
select Cell_no, COUNT(Cat_id)
from TableName
group by Cell_Number
having COUNT(Cat_id) > 1
But what i need is some thing like this.
select *
from TableName
group by Cell_Number
having COUNT(Cat_id) > 1
Pratik's answer is good but rather than using the IN operator (which only works for single values) you will need to JOIN back to the result set like this
SELECT t.*
FROM tableName t
INNER JOIN
(SELECT Cell_no, Name
FROM TableName
GROUP BY Cell_no , Name
HAVING COUNT(Cat_id) > 1) filter
ON t.Cell_no = filter.Cell_no AND t.Name = filter.Name
you just need to modify your query like below --
select * from tableName where (Cell_no, Name) in (
select Cell_no, Name from TableName
Group by Cell_no , Name
having COUNT(Cat_id) > 1
)
as asked in question you want to group by Cell_no and Name.. if so you need to change your query for group by columns and select part also.. as I have mentioned
This version requires only one pass over the data:
SELECT *
FROM (SELECT a.*
,COUNT(cat_id) OVER (PARTITION BY cell_no)
AS count_cat_id_not_null
FROM TableName a)
WHERE count_cat_id_not_null > 1;

Resources