How to joining table while using flatten logic in snowflake - snowflake-cloud-data-platform

I have used lateral flatten logic in Snowflake in the below query. The query works up to alias A.
I'm getting invalid identifier error when I use the join condition
based on the common column. ON B.product_id=A.product_id
SELECT A.ID, INDEX, purchase_list,
CASE WHEN INDEX = 1 and purchase_list NOT IN('121=find-values','122=find_results','123=item_details','',' ')
THEN purchase_list END as item_no
FROM (SELECT ID,index,d.value::string AS purchase_list FROM (
SELECT ID,c.value::string AS purchase_list
FROM table_1,lateral flatten(INPUT=>split(po_purchase_list, '|')) c
),
LATERAL flatten(INPUT=>split(purchase_list, ';')) d
) A -- The query would be correct till here
JOIN
table_2 B -- This is the table I need to join with table_1
ON B.product_id=A.product_id
WHERE date='2022-03-03'
AND b.item_src NOT IN('0','1','3','4')

from the error message it looks like it is not able to find the column product_id in one of the tables or CTE , can you include the column product_id in your SELECT statement for table A, and see if it works.

Related

Snowflake - is it possible to "merge" array output to table query

i have two inputs:
a. Table A with 3 columns: a ,b , c - with 7 rows
b. Table B with an array column d , the array has 7 values.
Is there a way to "merge" the table A and TABLE B in a query - so that the first row of A and the first cell value of B will printed in the same row ?
Input:
For example:
Table A- Column 1
a
b
c
Table A- Column 2
d
e
f
Table b - column 1 (and only)
k
r
j
OUTPUT
should be three columns:
two first columns : column a, b (from table a)
third column - which is column 1 from table 2
You can use Flatten to convert your array into a table. Then you just need to define ordering and how to join them together.
Here's an example, where I use a ROW_NUMBER() to provide an ordering. And since I added it to both tableA and the flattened tableB, it can also be used to join the records together.
If you have IDs for ordering or joining, then that might be slightly cleaner, but with the simple columns provided in the example, you need to do something like this to line up the array values to the table rows.
with tA as (
select col1, col2,
ROW_NUMBER() OVER(ORDER BY col1) rnum
from tableA
)
,tB as (
select
x.value::string col1,
ROW_NUMBER() OVER(ORDER BY 1) rnum
from tableB ,
lateral flatten(input => array) x
)
SELECT a.col1, a.col2, b.col1
FROM tA a
JOIN tB b
ON a.rnum = b.rnum;
There is no "first row" in databases. There is a first with respect to an order you place on the data. Thus there a number of way to get just the "first row" of table A and table B.
On is to only select the first rows, I will use CTE but it can be done in a sub-select also. Via a QUALIFY and ROW_NUMBER, and to make it 'stable' I will use the selected output column. After that to JOIN the two tables, I will use a CROSS-JOIN, but given there are only one row from both CTE's this will give just one output row. But this does not feel like what you want.
WITH first_from_table_a AS (
SELECT column1, column2
FROM table_a
QUALIFY ROW_NUMBER() OVER (ORDER BY column1) = 1
), first_from_table_b AS (
SELECT column1
FROM table_b
QUALIFY ROW_NUMBER() OVER (ORDER BY column1) = 1
)
SELECT a.column1, a.column2, b.column1
FROM first_from_table_a AS a
CROSS JOIN first_from_table_b AS b
The problem with this is, if there are other things you are want to do this over it doesn't scale.
FIRST_VALUE is a function that could also help, if you join your data on some other schema, and want to chose a value from a larger set, but really the problem needs to be clarified more.
Another way to consider your question is to use the same ROW_NUMBER idea, and join on those, thus:
WITH first_from_table_a AS (
SELECT column1,
column2,
ROW_NUMBER() OVER (ORDER BY column1) AS rn
FROM table_a
), first_from_table_b AS (
SELECT column1,
ROW_NUMBER() OVER (ORDER BY column1) AS rn
FROM table_b
)
SELECT a.column1, a.column2, b.column1
FROM first_from_table_a AS a
JOIN first_from_table_b AS b
ON a.rn = b.rn
ORDER BY a.rn

Merging two columns from two tables

I have to merge two columns from two unrelated tables with the same number of rows in another table, like
Table A:
AColumn
'ABC'
'152'
'XXX'
Table B:
BColumn
'FF'
'CD'
'91'
Expected result for the destination table (table C):
CColumn1 CColumn2
'ABC' 'FF'
'152' 'CD'
'XXX' '91'
Apparently this looks very simple but I can't find a way to achieve it.
My attempt would be something like:
SELECT A.AColumn as CColumn1, B.BColumn as CColumn2 into C
FROM A INNER JOIN B ON 1=1
but this obviously generates all the possible combinations over the elements, while I just want the first row from A matched with the first row from B, the second row with the second row, etc.
Any help?
You need to add a row_number to each table and join on that, here is an example using two CTEs:
with a as (
select AColumn, row_number() over(order by (select null)) rn
from Table1
),
b as (
select BColumn, row_number() over(order by (select null)) rn
from Table2
)
select a.AColumn, b.BColumn
from a full outer join b
on a.rn = b.rn
Sql Fiddle: http://sqlfiddle.com/#!18/291c7/4

SQL IN clause multiple columns and multiple value

This query is fine works.
SELECT * FROM TABLE WHERE 330110042 IN (iItem01,iItem02,iItem03,iItem04,iItem05,iItem_1,iItem_2,iItem_3,iItem_4,iItem_5,iItem_6,iItem_7,iItem_8,iItem_9,iItem_10,iItem_11,iItem_12,iItem_13,iItem_14,iItem_15,iItem_16,iItem_17,iItem_18,iItem_19,iItem_20,iItem_21,iItem_22,iItem_23,iItem_24,iItem_25,iItem_26,iItem_27,iItem_28,iItem_29,iItem_30)
But this query didnt work.
SELECT * FROM TABLE WHERE 330110042, 330110002, 330110002 IN (iItem01,iItem02,iItem03,iItem04,iItem05,iItem_1,iItem_2,iItem_3,iItem_4,iItem_5,iItem_6,iItem_7,iItem_8,iItem_9,iItem_10,iItem_11,iItem_12,iItem_13,iItem_14,iItem_15,iItem_16,iItem_17,iItem_18,iItem_19,iItem_20,iItem_21,iItem_22,iItem_23,iItem_24,iItem_25,iItem_26,iItem_27,iItem_28,iItem_29,iItem_30)
How i work in SQL Server?
It's difficult to tell your exact goal here, but one possibility would be to turn the list of values into a table structure of its own. A Common Table Expression might work:
;WITH Ids AS
(
SELECT 330110042 AS Id
UNION ALL
SELECT 330110002
)
SELECT t.*
FROM [Table] t
INNER JOIN Ids i ON t.iItem01 = i.Id OR t.iItem02 = i.Id OR...
But, maybe a solution with UNPIVOT would be more elegant. I presume that your table has a primary key column called Id:
;WITH Unpivoted AS
(
SELECT Id, ColName, ColValue
FROM (SELECT Id, iItem01, iItem02, iItem03
FROM [Table] t) p
UNPIVOT
(ColValue FOR ColName IN (iItem01, iItem02, iItem03)) AS unpvt
)
SELECT t.*
FROM [Table] t
WHERE EXISTS (SELECT 1 FROM Unpivoted u
WHERE t.Id = u.Id
AND u.ColValue IN (330110042, 330110002))
Of course, you would add all the necessary columns. I added only the first three for this example.

Hints are not allowed on recursive common table expression (CTE) references. Consider removing hint from recursive CTE reference 'CTE'

I have one Employee table here is table structure
Name varchar
GUID numeric
ParentGUID numeric
here is some sample data
NAME GUID ParentGUID
ABC 1 NULL
BCD 2 1
xyz 3 2
PQR 4 2
MRS 5 3
This table contains big hierarchy of Employee and manager.
I need to pick all the Employee coming under particular employee.
Ex. I need all the Employees coming under BCD, so result should be
xyz 3 2
PQR 4 2
here is my recursive query for that.
;WITH CTE (Name, GUID, ParentGUID)
AS
(
select distinct B.Name , B.GUID, B.ParentGUID
FROM
EMP B with (nolock)
union All
select a.Name , a.GUID, a.ParentGUID
FROM EMP a with (nolock)
inner join CTE C with (nolock) on a.ParentGUID = c.GUID
)
select *
FROM CTE B with (nolock) where B.Name in ('BCD')
But it's giving me error.
Msg 4150, Level 16, State 1, Line 1
Hints are not allowed on recursive common table expression (CTE) references. Consider removing hint from recursive CTE reference 'CTE'.
Can you anyone please help me to correct this query.
Your where B.Name in ('BCD') is what is filtering your result set to just the one row. Change it to the below and you should get the results you want:
;with cte (Name, GUID, ParentGUID)
as
(
select distinct B.Name
,B.GUID
,B.ParentGUID
from EMP B
where B.Name in ('BCD')
union All
select a.Name
,a.GUID
,a.ParentGUID
from EMP a
inner join CTE C
on a.ParentGUID = c.GUID
)
select *
from CTE
Completely removing the WITH (NOLOCK) only solve the error,
to use WITH (NOLOCK) in recursive CTE you just need to put it outside of WITH clause only
;with cte (Name, GUID, ParentGUID)
as
(
select distinct B.Name
,B.GUID
,B.ParentGUID
from EMP B
where B.Name in ('BCD')
union All
select a.Name
,a.GUID
,a.ParentGUID
from EMP a
inner join CTE C
on a.ParentGUID = c.GUID
)
select *
from cte WITH (NOLOCK);

need empty row in output between rows with data Report Builder 3.0 T-SQL

I have reports that pull 50 random records. i would like to insert a blank Row in the output between each row of data. for example, Rows 1,3,5,7... are populated with data, and even number rows are empty.
Thanks
CROSS APPLY with NULL valued table gives equal number of rows as original table.
Now we can generate ROW_NUMBER for two SELECTs and sort it by row number to get alternate values.
select C.id, C.name, ROW_NUMBER() OVER ( ORDER BY C.id) as seq from TableC C
UNION ALL
SELECT T.id, T.name, seq as seq
FROM
(
select T.id, T.name ,ROW_NUMBER() OVER ( ORDER by C.id ) as seq from TableC C
cross apply ( select NULL as id,NULL as name ) T
) T
ORDER BY seq
A very simple solution could be :
Select id+Temp id, name+Temp name from TableA A
Cross Apply
(select '' as 'Temp'
union all
Select null) X
If you have large number of columns, then create the concatenation of column_name + temp dynamically and use that in dynamic sql
for Demo Click on --> DEMO

Resources