What's equivalent to this hive query in snowflake?
The lateral view outer explode is supposed to create a column with 'a' and 'b' for each distinct record set.
select
o.*,
domain
from
(
select distinct group, program, track
from my_snowflake_table
) o
lateral view outer explode(
array(
'a',
'b'
)
) wt as domain
select distinct x."GROUP", x.program, x.track, z.value
from my_snowflake_table as x, lateral SPLIT_TO_TABLE('a.b', '.') as z
The example uses a static array('a', 'b') so it could be translated using CROSS JOIN:
select distinct x."GROUP", x.program, x.track, z.domain
from my_snowflake_table as x
CROSS JOIN (VALUES ('a'), ('b')) z(domain);
Related
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.
Tabel1 and Table 2
select p.id,q.description
from table1 p
join table2 q
on q.control_number
in unnest(p.results.control_number)
When I process this I'm getting the below error:
Cannot access field control_number on a value with type
ARRAY<STRUCT<control_number string,...., …>>
I have also tried un-nesting after the table like:
select p.id,q.f.description
from table1 p,Unnest(finder) f
join table2 q
on q.control_number in unnest(p.f.results.control_number)
But this also did not work.
Can anyone tell me what's wrong?
Another option
select p.id,q.description
from table1 p, table2 q
where q.control_number in (select control_number from p.finder)
Try the following in standard SQL:
with table1 as (
select '1' id, array[struct('a1' as control_number)] finder
UNION ALL
select '2' id, array[struct('a2' as control_number)] finder
UNION ALL
select '3' id, array[struct('a3' as control_number)] finder
),
table2 as (
select 'description for a1' description, 'a1' control_number
UNION ALL
select 'description for a2' description, 'a2' control_number
)
select p.id,q.description
from table1 p, unnest(p.finder) f join table2 q on q.control_number = f.control_number;
WITH clause is used to simulate data in your tables.
I am using an CROSS APPLY & and a custom-built XML function (instead UNPIVOT) in SQL Server 2012, to move values vertically within a table.
SELECT A.USERID
,B.[ITEM]
,B.VALUE
FROM #UPLOAD A
CROSS APPLY [DBO].[TVF-XML-UNPIVOT-ROW]( (SELECT A.* FOR XML RAW) ) B
WHERE [ITEM] NOT IN ('USERID' )
The query successfully unpivots everything, but in the process, converts spaces, dashes, brackets, etc into their respective UNICODE value, as follows:
EMPID ITEM VALUE
123 _x0027_October_x0020_Bonus_x0020__x0028_Perm_x0020__x002B__x0020_Temp_x0029_ 28.01
Expected output:
EMPID ITEM VALUE
123 October Bonus (Perm + Temp) 28.01
Below is the function, some temp values you can use, and the Code itself. Any how to format the string without the unicode values?
CREATE FUNCTION [dbo].[tvf-XML-UnPivot-Row](#XML xml)
Returns Table
As
Return (
Select Item = xAttr.value('local-name(.)', 'varchar(100)')
,Value = xAttr.value('.','varchar(max)')
From #XML.nodes('//#*') xNode(xAttr)
)
DROP TABLE #UPLOAD
CREATE TABLE #UPLOAD (USERID INT,['October Bonus (Perm + Temp)] FLOAT NOT NULL );
INSERT INTO #UPLOAD VALUES (123,20.3),(240,35)
SELECT A.USERID
,B.[ITEM]
,B.VALUE
FROM #UPLOAD A
CROSS APPLY [DBO].[TVF-XML-UNPIVOT-ROW]( (SELECT A.* FOR XML RAW) ) B
WHERE [ITEM] NOT IN ('USERID' )
EDIT: I recall now that you were NOT 2016+
If 2016+ You can use this function instead of the XML approach
CREATE FUNCTION [dbo].[tvf-JSON-Unpivot-Row](#json varchar(max))
Returns Table
As Return
Select [Key]
,Value
From OpenJson(#json)
Examples
Select A.ID
,B.*
from YourTable A
Cross Apply [dbo].[tvf-JSON-Unpivot-Row]( (Select A.* For JSON Path,Without_Array_Wrapper ) ) B
Where [Key] not in ('ID')
or to include NULLs
Select A.ID
,B.*
from YourTable A
Cross Apply [dbo].[tvf-JSON-Unpivot-Row]( (Select A.* For JSON Path,Without_Array_Wrapper,INCLUDE_NULL_VALUES ) ) B
Where [Key] not in ('ID')
This would be an easy join except: Table A is explicit for all times and values, but Table B only records rows when the there is a change from the previous value. In looking at Table B one can easily infer the missing times and values, but how to put that into a query?
Data in A.time contains every minute and a corresponding A.Value.
A.Time...........A.Value
9:00...............3.4
9:01...............5.0
9:02...............5.3
9:03...............5.3
9:04...............5.3
and so on…..
Table B only contains rows where the B.value has changed from the previous value.
B.Time..............B.Value
9:00...................4
9:01...................4.1
This is blank, but I know it to be 9:02 / 4.1
This is blank, but I know it to be 9:03 / 4.1
9:04....................4.7
and so on…
I need to do a query that links A.Time and B.Value, but I need the query to understand that a missing time in Table B should be substituted by the B.value of the first B.Time preceeding it.
Final table should be
A.Time...............B.Value
9:00...................4
9:01...................4.1
9:02...................4.1
9:03...................4.1
9:04...................4.7
I am currently writing this for SQL Server, but I need an Oracle solution too
Thanks in advance;
In Oracle, you can LEFT JOIN to get all the times and then use LAST_VALUE(b.value) IGNORE NULLS... to fill in the blanks. (NOTE: the ROWS BETWEEN... part is redundant with the ORDER BY in the OVER() clause, but I like it for extra clarity).
Like this:
SELECT a.time,
LAST_VALUE (b.VALUE)
IGNORE NULLS
OVER (PARTITION BY NULL
ORDER BY a.time
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
FROM table_a a
LEFT JOIN table_b b ON b.time = a.time
ORDER BY a.time;
Here is a full example with test data:
with table_a ( time, value ) as
( SELECT '9:00', 3.4 FROM DUAL UNION ALL
SELECT '9:01', 5.0 FROM DUAL UNION ALL
SELECT '9:02', 5.3 FROM DUAL UNION ALL
SELECT '9:03', 5.3 FROM DUAL UNION ALL
SELECT '9:04', 5.3 FROM DUAL ),
table_b ( time, value ) as
( SELECT '9:00', 4 FROM DUAL UNION ALL
SELECT '9:01', 4.1 FROM DUAL UNION ALL
SELECT '9:04', 4.7 FROM DUAL )
SELECT a.time,
LAST_VALUE (b.VALUE)
IGNORE NULLS
OVER (PARTITION BY NULL
ORDER BY a.time
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
FROM table_a a
LEFT JOIN table_b b ON b.time = a.time
ORDER BY a.time;
An alternative (which might work on SQL Server) is to use OUTER APPLY. Like so:
SELECT a.time, b.value
FROM table_a a
OUTER APPLY ( SELECT *
FROM table_b b
WHERE b.time <= a.time
ORDER BY b.time desc
FETCH FIRST 1 ROW ONLY ) b
ORDER BY a.time;
Basically, this finds the most recent non-null value from table B for each row in table A.
SQL*SERVER Solution
Here is the OUTER APPLY syntax translated to SQL*Server:
with table_a ( time, value ) as
( SELECT '9:00', 3.4 UNION ALL
SELECT '9:01', 5.0 UNION ALL
SELECT '9:02', 5.3 UNION ALL
SELECT '9:03', 5.3 UNION ALL
SELECT '9:04', 5.3 ),
table_b ( time, value ) as
( SELECT '9:00', 4 UNION ALL
SELECT '9:01', 4.1 UNION ALL
SELECT '9:04', 4.7 )
SELECT a.time, b.value
FROM table_a a OUTER APPLY (
SELECT * FROM table_b b
WHERE b.time <= a.time
ORDER BY b.time desc
OFFSET 0 ROWS
FETCH NEXT 1 ROWS ONLY ) b
ORDER BY a.time;
This should really be allowed - I do not understand why it is not.
SELECT *
FROM (
SELECT *
FROM MyTable
)
In SQL Server it is allowed, but the inner select has to be given a name, such as:
SELECT *
FROM (
SELECT *
FROM MyTable
) m
When a name is not supplied it will throw an incorrect syntax error near ')' message.
If you add a table alias it should work:
SELECT *
FROM (
SELECT *
FROM MyTable
) as A
You are missing an 'alias' on the sub-query
(I added an alias 'X' )
SELECT *
FROM (
SELECT *
FROM MyTable
) X
There are at least two ways to accomplish this, but what you might be looking for is a Common Table Expression (CTE), introduced in SQL Server 2005.
From the above link:
USE AdventureWorks;
GO
WITH Sales_CTE (SalesPersonID, NumberOfOrders, MaxDate)
AS
(
SELECT SalesPersonID, COUNT(*), MAX(OrderDate)
FROM Sales.SalesOrderHeader
GROUP BY SalesPersonID
)
SELECT E.EmployeeID, OS.NumberOfOrders, OS.MaxDate,
E.ManagerID, OM.NumberOfOrders, OM.MaxDate
FROM HumanResources.Employee AS E
JOIN Sales_CTE AS OS
ON E.EmployeeID = OS.SalesPersonID
LEFT OUTER JOIN Sales_CTE AS OM
ON E.ManagerID = OM.SalesPersonID
ORDER BY E.EmployeeID;
GO
Alternately, you can create a View, which is a permanent table-shaped representation of a query that you can access by name:
USE AdventureWorks ;
GO
IF OBJECT_ID ('hiredate_view', 'V') IS NOT NULL
DROP VIEW hiredate_view ;
GO
CREATE VIEW hiredate_view
AS
SELECT c.FirstName, c.LastName, e.EmployeeID, e.HireDate
FROM HumanResources.Employee e JOIN Person.Contact c on e.ContactID = c.ContactID ;
GO
SELECT * FROM hiredate_view