I have a MySQL query that I want to convert into a snowflake.
MySQL query :
WITH t AS (
select id,
date,
copt,
split(copt, '|') [ 1 ] as "abc",
split(copt, '|') [ 2 ] as "def",
split(copt, '|') [ 3 ] as "xyz",
from tablename
where id in (
123,
456,
789,
)
and date >= dateadd('day', -6, to_date('2021-12-17'))
and date <= date '2021-12-17'
and copt like '%|%|%|%|%|%|%|%|%|%|%'
)
SELECT t.id,
t.date,
catId,
REPLACE(productId, '_', '') as productId,
FROM t
CROSS JOIN UNNEST(
split(t."abc", '_'),
split(t."def", '_'),
split(t."xyz", '_'),
) as x(catId, productId, quantity)
where productid != ''
order by id
I have tried to replace UNNEST() with FLATTEN() but didn't succeed.
Can anyone help me out here to convert this query from MySQL to Snowflake?
It doesn't appear the MySQL has UNNEST support, so I could not read the manual on that.
Also you have not provided any example input, and the output you are expecting, But assuming you abc, def, & xzy are arrays of independent sizes, and you are want all permutations the following SQL should work:
WITH cte_t(id,date, abc, def, xyz, productid) AS (
SELECT * FROM VALUES
(1, '2022-01-23'::date, 'a_b_c_d', 'd_e_f', 'x_y_w', 'not empty'),
(2, '2022-01-23'::date, 'a_d', 'd_f', 'y_w', 'not empty'),
(3, '2022-01-23'::date, 'a_c_d', 'f', 'y1_y2_w', 'not empty')
)
SELECT
t.id,
t.date,
a.value AS catid,
b.value AS productid,
c.value AS quantity
FROM cte_t AS t
,LATERAL SPLIT_TO_TABLE(t.abc, '_') a
,LATERAL SPLIT_TO_TABLE(t.def, '_') b
,LATERAL SPLIT_TO_TABLE(t.xyz, '_') c
WHERE productid != ''
gives:
ID
DATE
CATID
PRODUCTID
QUANTITY
1
2022-01-23
a
d
x
1
2022-01-23
b
d
x
1
2022-01-23
c
d
x
1
2022-01-23
d
d
x
1
2022-01-23
a
e
x
1
2022-01-23
b
e
x
1
2022-01-23
c
e
x
1
2022-01-23
d
e
x
1
2022-01-23
a
f
x
1
2022-01-23
b
f
x
1
2022-01-23
c
f
x
1
2022-01-23
d
f
x
1
2022-01-23
a
d
y
1
2022-01-23
b
d
y
1
2022-01-23
c
d
y
1
2022-01-23
d
d
y
1
2022-01-23
a
e
y
1
2022-01-23
b
e
y
1
2022-01-23
c
e
y
1
2022-01-23
d
e
y
1
2022-01-23
a
f
y
1
2022-01-23
b
f
y
1
2022-01-23
c
f
y
1
2022-01-23
d
f
y
1
2022-01-23
a
d
w
1
2022-01-23
b
d
w
1
2022-01-23
c
d
w
1
2022-01-23
d
d
w
1
2022-01-23
a
e
w
1
2022-01-23
b
e
w
1
2022-01-23
c
e
w
1
2022-01-23
d
e
w
1
2022-01-23
a
f
w
1
2022-01-23
b
f
w
1
2022-01-23
c
f
w
1
2022-01-23
d
f
w
2
2022-01-23
a
d
y
2
2022-01-23
d
d
y
2
2022-01-23
a
f
y
2
2022-01-23
d
f
y
2
2022-01-23
a
d
w
2
2022-01-23
d
d
w
2
2022-01-23
a
f
w
2
2022-01-23
d
f
w
3
2022-01-23
a
f
y1
3
2022-01-23
c
f
y1
3
2022-01-23
d
f
y1
3
2022-01-23
a
f
y2
3
2022-01-23
c
f
y2
3
2022-01-23
d
f
y2
3
2022-01-23
a
f
w
3
2022-01-23
c
f
w
3
2022-01-23
d
f
w
Ok, that was more data the I was expecting, but there you go.
If how ever those three arrays are of the same size then you can use one SPLIT_TO_TALBE and two SPLIT_PART:
WITH cte_t(id,date, abc, def, xyz, productid) AS (
SELECT * FROM VALUES
(1, '2022-01-23'::date, 'a_b_c', 'd_e_f', 'x_y_w', 'not empty')
)
SELECT
t.id,
t.date,
a.value AS catid,
split_part(t.def, '_', a.index) AS productid,
split_part(t.xyz, '_', a.index) AS quantity
FROM cte_t AS t
,LATERAL SPLIT_TO_TABLE(t.abc, '_') a
WHERE productid != ''
giving
ID
DATE
CATID
PRODUCTID
QUANTITY
1
2022-01-23
a
d
x
1
2022-01-23
b
e
y
1
2022-01-23
c
f
w
Related
I have two tables which I want to join. I have tried LEFT, RIGHT, INNER joins on Table but no success.
Table1
Name1 Name2
------------
A 1
B 2
C 3
D 1
Table2
Name2 Name3
------------
1 x
1 y
2 x
3 x
3 y
3 z
4 y
The result for what I am looking for is:
ResultTable
Name1 Name2 Name3
------------------
A 1 x
A 1 y
B 2 x
C 3 x
C 3 y
C 3 z
D 1 x
D 1 y
You can try this using SQL Server Join Reference.
Select Table1.Name1, Table1.Name2, Table2.Name3
from Table1
inner join Table2 on Table1.Name2 = Table2.Name2
Here is the implementation.
create table Table1 (Name1 varchar(5), Name2 int)
Insert into Table1 Values ('A',1), ('B',2), ('C',3), ('D',1)
create table Table2 (Name2 int, Name3 varchar(5))
Insert into Table2
Values (1, 'x'), (1, 'y'), (2, 'x'), (3, 'x'), (3, 'y'), (3, 'z'), (4, 'y')
Select Table1.Name1, Table1.Name2, Table2.Name3
from Table1
inner join Table2 on Table1.Name2 = Table2.Name2
The output is as shown below.
Name1 Name2 Name3
----------------------
A 1 x
A 1 y
B 2 x
C 3 x
C 3 y
C 3 z
D 1 x
D 1 y
Online Demo
I have data similar to below. I need to group the status column based on the occurrence of data.
Id Status Value
1 K 1
2 K 3
3 K 2
4 B 2
5 B 3
6 K 6
7 J 5
8 J 2
I want data as below
Status Value
K 6
B 5
K 6
J 7
I need the cumulative sum of the value column.In the status column if the data is same consecutively, then I need to add the value columns. I cannot apply group by. In the example given K is repeated twice, because they are not consecutive.
I have tried below query, but it doesn't work as required.
select Status,
(select sum(value)
from table t2
where
t2.Status = t.Status and
t2.SNO <= t.SNO
) as total
from table t;
This is a Gaps and Islands Question
I tackle these by using the incrementing Id and combing this with ROW_NUMBER window function
--Using a CTE just to replicate the sample data
;WITH cteX (Id,Status,Value)
AS(
SELECT 1,'K', 1 UNION ALL
SELECT 2,'K', 3 UNION ALL
SELECT 3,'K', 2 UNION ALL
SELECT 4,'B', 2 UNION ALL
SELECT 5,'B', 3 UNION ALL
SELECT 6,'K', 6 UNION ALL
SELECT 7,'J', 5 UNION ALL
SELECT 8,'J', 2
)
SELECT
Grp = Id - ROW_NUMBER()OVER( PARTITION BY X.Status ORDER BY X.Id)
, X.Id
, X.Status
, X.Value
FROM
cteX X
ORDER BY
X.Id
This gives this result set, note the Grp column
Grp Id Status Value
------- ------- ------- -------
0 1 K 1
0 2 K 3
0 3 K 2
3 4 B 2
3 5 B 3
2 6 K 6
6 7 J 5
6 8 J 2
Then combine with a CTE or derived table you can get your expected output
--Using a CTE just to replicate the sample data
;WITH cteX (Id,Status,Value)
AS(
SELECT 1,'K', 1 UNION ALL
SELECT 2,'K', 3 UNION ALL
SELECT 3,'K', 2 UNION ALL
SELECT 4,'B', 2 UNION ALL
SELECT 5,'B', 3 UNION ALL
SELECT 6,'K', 6 UNION ALL
SELECT 7,'J', 5 UNION ALL
SELECT 8,'J', 2
)
SELECT Y.Status
, Value = SUM(Y.Value)
FROM
(
SELECT TOP 100 PERCENT
Grp = Id - ROW_NUMBER()OVER( PARTITION BY X.Status ORDER BY X.Id)
, X.Id
, X.Status
, X.Value
FROM
cteX X
ORDER BY
X.Id
) Y
GROUP BY
Y.Grp, Y.Status
Output
Status Value
------- -------
B 5
J 7
K 6
K 6
Update Question include "Preserve order" solution
Just include an Order by MIN(Id)
--Using a CTE just to replicate the sample data
;WITH cteX (Id,Status,Value)
AS(
SELECT 1,'K', 1 UNION ALL
SELECT 2,'K', 3 UNION ALL
SELECT 3,'K', 2 UNION ALL
SELECT 4,'B', 2 UNION ALL
SELECT 5,'B', 3 UNION ALL
SELECT 6,'K', 6 UNION ALL
SELECT 7,'J', 5 UNION ALL
SELECT 8,'J', 2
)
SELECT
Y.[Status]
,[Value] = SUM(Y.[Value])
FROM
(
SELECT
Grp = Id - ROW_NUMBER()OVER( PARTITION BY X.[Status] ORDER BY X.Id)
, X.Id
, X.[Status]
, X.[Value]
FROM
cteX X
) Y
GROUP BY
Y.Grp, Y.[Status]
ORDER BY
MIN(Y.Id) --preserve the Status Order
Output
Status Value
------- -------
K 6
B 5
K 6
J 7
I have a table which has data that appears as:
Staion Date Temperature
A 2015-07-31 8
B 2015-07-31 6
C 2015-07-31 8
A 2003-02-21 4
B 2003-02-21 7
C 2003-02-21 7
For each date I need to create arrays so that it has the following combination:
c1 = (A + B)/2, c2 = (A + B + C)/3 and c3 = (B + C)/2
Right I am doing three different inner join on the table itself and doing a final inner join to achieve the following as result:
Date c1 c2 c3
2015-07-31 7 7.33 7
2003-02-21 5.5 6 7
Is there a cleaner way to do this?
No need for a JOIN, you could simply use a GROUP BY and an aggregation function:
WITH CTE AS
(
SELECT [Date],
MIN(CASE WHEN Staion = 'A' THEN Temperature END) A,
MIN(CASE WHEN Staion = 'B' THEN Temperature END) B,
MIN(CASE WHEN Staion = 'C' THEN Temperature END) C
FROM dbo.YourTable
GROUP BY [date]
)
SELECT [Date],
(A+B)/2 c1,
(A+B+C)/3 c2,
(B+C)/2 c3
FROM CTE;
SUM Function is very useful in such cases:
SELECT
c1 = SUM(CASE WHEN Staion IN ('A', 'B') THEN Temperature ELSE 0 END) / 2,
c2 = SUM(Temperature) / 3,
c3 = SUM(CASE WHEN Staion IN ('B', 'C') THEN Temperature ELSE 0 END) / 2,
[Date]
FROM dbo.Table
GROUP BY [Date]
You can do it with just two joins and almost literally the formulas you've provided:
declare #t table (Station char(1) not null,[Date] date not null, Temperature int not null)
insert into #t(Station,[Date],Temperature) values
('A','20150731',8),
('B','20150731',6),
('C','20150731',8),
('A','20030221',4),
('B','20030221',7),
('C','20030221',7)
select
B.[Date],
c1 = (A.Temperature + B.Temperature)/2.0,
c2 = (A.Temperature + B.Temperature + C.Temperature)/3.0,
c3 = (B.Temperature + C.Temperature)/2.0
from
#t B
inner join
#t A
on
B.[Date] = A.[Date]
inner join
#t C
on
B.[Date] = C.[Date]
where
A.Station = 'A' and
B.Station = 'B' and
C.Station = 'C'
Result:
Date c1 c2 c3
---------- --------------- ----------- ----------
2015-07-31 7.000000 7.333333 7.000000
2003-02-21 5.500000 6.000000 7.000000
You can use pivot and calculation on pivoted data as below:
select [Date], c1 = (A+B)/2.0, c2 = (A+B+C)/3.0, C3 = (B+C)/2.0 from
( select * from #yourstation ) s
pivot (max(temparature) for station in ([A], [B], [C])) p
Your input table:
create table #yourStation (station char(1), date date, Temparature int)
insert into #yourStation (station, date, Temparature) values
('A','2015-07-31', 8 )
,('B','2015-07-31', 6 )
,('C','2015-07-31', 8 )
,('A','2003-02-21', 4 )
,('B','2003-02-21', 7 )
,('C','2003-02-21', 7 )
I have a table like so
ID Node ParentID
1 A 0
2 B 1
3 C 1
4 D 2
5 E 2
6 F 3
7 G 3
8 H 3
9 I 4
10 J 4
11 K 10
12 L 11
I need a query to generate a 'position' field with the order that a node appears within its parent. Example below
ID Node ParentID Positon
1 A 0 0
2 B 1 0
3 C 1 1
4 D 2 0
5 E 2 1
6 F 3 0
7 G 3 1
8 H 3 2
9 I 4 0
10 J 4 1
11 K 10 0
12 L 11 0
select *
, row_number() over (partition by ParentID order by ID) - 1 as Position
from YourTable
As an update query:
update yt
set Position = nr
from (
select *
, row_number() over (partition by ParentID order by ID) - 1 rn
from YourTable
) yt
To update position in the original table join it to already suggested statement, either as sub-query or CTE:
;with cte (ID, Pos)
as (
select ID, row_number() over (partition by ParentID order by ID) - 1
from [Table]
)
update T
set T.Position = cte.Pos
from [Table] T
join cte on cte.ID = T.ID
Dear All, please help me since I'm newbie in SQL Server. I have a select query that currently produces the following results:
DoctorName
Team
Visit date
dr. As
A
5
dr. Sc
A
4
dr. Gh B 6
dr. Nd C 31
dr As A 7
Using the following query:
SELECT d.DoctorName, t.TeamName, ca.VisitDate FROM cActivity AS ca
INNER JOIN doctor AS d ON ca.DoctorId = d.Id
INNER JOIN team AS t ON ca.TeamId = t.Id
WHERE ca.VisitDate BETWEEN '1/1/2010' AND '1/31/2010'
I want to produce the following:
DoctorName Team 1 2 3 4 5 6 7 ... 31 Visited
dr. As A x x ... 2 times
dr. Sc A x ... 1 times
dr. Gh B x ... 1 times
dr. Nd C ... x 1 times
Use:
SELECT d.doctorname,
t.teamname,
MAX(CASE WHEN ca.visitdate = 1 THEN 'x' ELSE NULL END) AS 1,
MAX(CASE WHEN ca.visitdate = 2 THEN 'x' ELSE NULL END) AS 2,
MAX(CASE WHEN ca.visitdate = 3 THEN 'x' ELSE NULL END) AS 3,
...
MAX(CASE WHEN ca.visitdate = 31 THEN 'x' ELSE NULL END) AS 31,
COUNT(*) AS visited
FROM CACTIVITY ca
JOIN DOCTOR d ON d.id = ca.doctorid
JOIN TEAM t ON t.id = ca.teamid
WHERE ca.visitdate BETWEEN '1/1/2010' AND '1/31/2010'
GROUP BY d.doctorname, t.teamname