How can I convert the array of integers to rows? - snowflake-cloud-data-platform

I have a table that has:
id, timestamp, [array of integers]
How can I convert the array of integers to rows? Almost the opposite of array_agg.
eg,
1, ts, [1,2,3]
2, ts, [7,8,9]
would be
1, ts, 1
1, ts, 2
1, ts, 3
2, ts, 7
2, ts, 8
2, ts, 9
I've read through https://docs.snowflake.net/manuals/sql-reference/udf-js-table-functions.html but it's not clear that this will work. I am trying to avoid using a scripting language outside of the database. Thanks!

Use FLATTEN. It has various options, including things like the value of the field, but also index in the array etc.
A full example below:
create or replace table x(i int, s string, v variant);
insert into x
select column1, column2, parse_json(column3) from values
(1, 'ts1', '[1,2,3]'),
(2,'ts2','[7,8,9]');
select * from x;
---+-----+------+
I | S | V |
---+-----+------+
1 | ts1 | [ |
| | 1, |
| | 2, |
| | 3 |
| | ] |
2 | ts2 | [ |
| | 7, |
| | 8, |
| | 9 |
| | ] |
---+-----+------+
select i, s, f.value as newcolumn from x, table(flatten(x.v)) f;
---+-----+-----------+
I | S | NEWCOLUMN |
---+-----+-----------+
1 | ts1 | 1 |
1 | ts1 | 2 |
1 | ts1 | 3 |
2 | ts2 | 7 |
2 | ts2 | 8 |
2 | ts2 | 9 |
---+-----+-----------+

Related

How to move columns to rows in a SQL Server select?

I have a SQL Server 2016 temp table that looks like this:
SECTION_NAME SORT_ORDER COL1 COL2 COL3 COL4 COL5 COL6 COL7 COL8 COL9 COL10
ONE 1 A B C D E F G H I J
ONE 2 C D E F G H I X Y Z
I am only selecting the COL columns and want each records COL columns to be on a separate row, like this:
SELECT * FROM #TEMPTABLE
A
B
C
D
E
etc
How can I do that? I don't know PIVOT very well so not sure if I can use that. Thanks!
You need to "unpivot" which I prefer to do using cross apply and values, like this
SELECT
row_number() over (order by SECTION_NAME, SORT_ORDER, ca.value) as ID
, section_name
, sort_order
, ca.value
FROM pivoted
CROSS APPLY (
VALUES
(col1)
, (col2)
, (col3)
, (col4)
, (col5)
, (col6)
, (col7)
, (col8)
, (col9)
, (col10)
) AS ca(value)
which produces:
+----+--------------+------------+-------+
| ID | section_name | sort_order | value |
+----+--------------+------------+-------+
| 1 | ONE | 1 | A |
| 2 | ONE | 1 | B |
| 3 | ONE | 1 | C |
| 4 | ONE | 1 | D |
| 5 | ONE | 1 | E |
| 6 | ONE | 1 | F |
| 7 | ONE | 1 | G |
| 8 | ONE | 1 | H |
| 9 | ONE | 1 | I |
| 10 | ONE | 1 | J |
| 11 | ONE | 2 | C |
| 12 | ONE | 2 | D |
| 13 | ONE | 2 | E |
| 14 | ONE | 2 | F |
| 15 | ONE | 2 | G |
| 16 | ONE | 2 | H |
| 17 | ONE | 2 | I |
| 18 | ONE | 2 | X |
| 19 | ONE | 2 | Y |
| 20 | ONE | 2 | Z |
+----+--------------+------------+-------+
see this demo

How do I multiply 2 cols from 2 tables for 2 different conditions

I have 2 tables Table A (6 columns 100 rows) and Table B (6 columns 2 rows).
Table A contains the following columns:
Name: same for all rows
Date: chronological dates
V1,V2,V3,V4: 4 columns with numerical values
Table B contains the following columns:
Name: same as table A
Model: 2 different values
V1,V2,V3,V4 : 4 columns with numerical values (values of table A and tableB not same)
TableA:
+------+----------+----+----+----+----+
| Name | Date | V1 | V2 | V3 | V4 |
+------+----------+----+----+----+----+
| abc | 1/12020 | 1 | 2 | 3 | 4 |
| abc | 2/1/2020 | 2 | 3 | 5 | 1 |
| abc | 3/1/2020 | 1 | 4 | 2 | 1 |
+------+----------+----+----+----+----+
Table B:
+------+-------+----+----+----+----+
| Name | Model | V1 | V2 | V3 | V4 |
+------+-------+----+----+----+----+
| abc | AA | 2 | 3 | 1 | 4 |
| abc | BB | 1 | 3 | 4 | 5 |
+------+-------+----+----+----+----+
I need to multiply V1, V2, V3, V4 values of Table B with the same from Table A and create a new table, Table C, where Name, Date, Model, V1, V2, V3, V4 values will be there.
For each date there will be 2 model rows with multiplication results of V1V1, V2V2, V3V3, V4V4. The result will look like below:
Table C:
+------+----------+-------+----+----+----+----+
| Name | Date | Model | V1 | V2 | V3 | V4 |
+------+----------+-------+----+----+----+----+
| abc | 1/1/2020 | AA | 2 | 6 | 3 | 16 |
| abc | 1/1/2020 | BB | 1 | 6 | 12 | 20 |
| abc | 2/1/2020 | AA | 4 | 9 | 5 | 4 |
| abc | 2/1/2020 | BB | 2 | 9 | 20 | 5 |
| abc | 3/1/2020 | AA | 2 | 12 | 2 | 4 |
| abc | 3/1/2020 | BB | 1 | 12 | 8 | 5 |
+------+----------+-------+----+----+----+----+
Try this:
-- Mock-up Data --
DECLARE #TableA table (
[Name] varchar(10), [Date] date, V1 int, V2 int, V3 int, V4 int
);
INSERT INTO #TableA VALUES
( 'abc', '01/01/2020', 1, 2, 3, 4 ),
( 'abc', '02/01/2020', 2, 3, 5, 1 ),
( 'abc', '03/01/2020', 1, 4, 2, 1 );
DECLARE #TableB table (
[Name] varchar(10), Model varchar(2), V1 int, V2 int, V3 int, V4 int
);
INSERT INTO #TableB VALUES
( 'abc', 'AA', 2, 3, 1, 4 ),
( 'abc', 'BB', 1, 3, 4, 5 );
-- Get resultset --
SELECT
a.[Name], a.[Date], b.Model
, b.V1 * a.V1 AS V1
, b.V2 * a.V2 AS V2
, b.V3 * a.V3 AS V3
, b.V4 * a.V4 AS V4
FROM #TableA a
LEFT JOIN #TableB b
ON a.[Name] = b.[Name];
Returns
+------+------------+-------+----+----+----+----+
| Name | Date | Model | V1 | V2 | V3 | V4 |
+------+------------+-------+----+----+----+----+
| abc | 2020-01-01 | AA | 2 | 6 | 3 | 16 |
| abc | 2020-01-01 | BB | 1 | 6 | 12 | 20 |
| abc | 2020-02-01 | AA | 4 | 9 | 5 | 4 |
| abc | 2020-02-01 | BB | 2 | 9 | 20 | 5 |
| abc | 2020-03-01 | AA | 2 | 12 | 2 | 4 |
| abc | 2020-03-01 | BB | 1 | 12 | 8 | 5 |
+------+------------+-------+----+----+----+----+
Note:
I'm sure you know this, however, the LEFT JOIN ensures all data from TableA is returned regardless of a match in TableB. Also, while I didn't do it here, you will probably want to add an ORDER BY.

Update first table based on values from second table

I have two tables:
- #CAMERC
- #CAMERC_LOG
I have to update column #CAMERC.MERC_LPR with values from column #CAMERC_LOG.MERC_LPR.
Records must match on MERC_KEY, but only one record must be taken from #CAMERC_LOG - with highest MERC_KEY_LOG, and #CAMERC_LOG.MERC_LPR must not be null or 0.
My problem is updating one table based on results from second table. I don't know how to properly make such an update?
Table #CAMERC:
+----------+----------+
| MERC_KEY | MERC_LPR |
+----------+----------+
| 1 | 0.0000 |
| 2 | NULL |
| 3 | 0.0000 |
| 4 | 0.0000 |
+----------+----------+
Table #CAMERC_LOG:
+----------+--------------+----------+
| MERC_KEY | MERC_KEY_LOG | MERC_LPR |
+----------+--------------+----------+
| 1 | 1 | 1.1000 |
| 1 | 2 | 2.3000 |
| 2 | 3 | 3.4000 |
| 2 | 4 | 4.4000 |
| 1 | 5 | 7.8000 |
| 1 | 6 | NULL |
| 2 | 7 | 0.0000 |
| 2 | 8 | 12.4000 |
| 3 | 1 | 12.1000 |
| 3 | 2 | 42.3000 |
| 3 | 3 | 43.4000 |
| 3 | 4 | 884.4000 |
| 4 | 5 | 57.8000 |
| 4 | 6 | NULL |
| 4 | 7 | 0.0000 |
| 4 | 8 | 412.4000 |
+----------+--------------+----------+
Code for table creation:
DECLARE #CAMERC TABLE
(
MERC_KEY INT,
MERC_LPR DECIMAL(10,4)
)
DECLARE #CAMERC_LOG TABLE
(
MERC_KEY INT,
MERC_KEY_LOG INT,
MERC_LPR DECIMAL(10,4)
)
INSERT INTO #CAMERC(MERC_LPR, MERC_KEY) VALUES(0, 1),(NULL,2),(0,3),(0,4)
INSERT INTO #CAMERC_LOG(MERC_LPR, MERC_KEY, MERC_KEY_LOG) VALUES(1.1, 1,1),(2.3,1,2),(3.4,2,3),(4.4,2,4),(7.8, 1,5),(NULL,1,6),(0,2,7),(12.4,2,8),
(12.1, 3,1),(42.3,3,2),(43.4,3,3),(884.4,3,4),(57.8, 4,5),(NULL,4,6),(0,4,7),(412.4,4,8)
Try this:
WITH DataSource AS
(
SELECT MERC_KEY
,ROW_NUMBER() OVER (PARTITION BY MERC_KEY ORDER BY MERC_KEY_LOG DESC) AS [RowID]
,MERC_LPR
FROM #CAMERC_LOG
WHERE MERC_LPR IS NOT NULL
AND MERC_LPR <> 0
)
UPDATE #CAMERC
SET MERC_LPR = B.[MERC_LPR]
FROM #CAMERC A
INNER JOIN DataSource B
ON A.[MERC_KEY] = B.[MERC_KEY]
AND B.[RowID] = 1
SELECT *
FROM #CAMERC
The idea is to eliminated the invalid records from the #CAMER_LOG and then using ROW_NUMBER to order the rows by MERC_KEY_LOG. After that, we are performing UPDATE by only where RowID = 1.

Add one with same foreign key at row sql server

I have a problem on sql server.
How to get running number from foreign key in one time select data from table?
example :
I have one table such as
-----------------
| id | pid | desc |
-----------------
| 1 | 1 | a |
| 2 | 1 | b |
| 3 | 1 | c |
| 4 | 2 | d |
| 5 | 2 | e |
| 6 | 2 | f |
| 7 | 2 | g |
| 8 | 3 | h |
| 9 | 3 | i |
| 10 | 1 | j |
| 11 | 1 | k |
-----------------
I want to get result as below
------------------------
| id | pid | desc | rec |
------------------------
| 1 | 1 | a | 1 |
| 2 | 1 | b | 2 |
| 3 | 1 | c | 3 |
| 4 | 2 | d | 1 |
| 5 | 2 | e | 2 |
| 6 | 2 | f | 3 |
| 7 | 2 | g | 4 |
| 8 | 3 | h | 1 |
| 9 | 3 | i | 2 |
| 10 | 1 | j | 4 |
| 11 | 1 | K | 5 |
------------------------
In above tables foreign key ('pid') Column has values 1 to 3 in different row numbers.
I tried to get the running number from each 'pid' field name.
I havn't found any way to do this,
Can I do that? Can some one help me? am still newbie at sql server
Try this
SELECT
id,
pid,
[desc],
Row_Number() OVER (PARTITION BY pid ORDER BY id) AS rec
FROM <yourtable>
ORDER BY id
You can use Ranking function in SQL Server 2005+ to accomplish that,
So here is your query
Select Row_Number() over (partition by pid order by id) as rec , * from Table

Add Summary cost one by one with same foreign key at row sql server

I have a problem on sql server to get running summary of cost from foreign key in one time select data from table?
example : I have one table such as
-----------------
| id | pid | Cost |
-----------------
| 1 | 1 | 5 |
| 2 | 1 | 4 |
| 3 | 1 | 3 |
| 4 | 2 | 1 |
| 5 | 2 | 3 |
| 6 | 2 | 4 |
| 7 | 2 | 5 |
| 8 | 3 | 6 |
| 9 | 3 | 7 |
| 10 | 1 | 3 |
| 11 | 1 | 2 |
-----------------
I want to get result as below
------------------------
| id | pid | cost | sum |
------------------------
| 1 | 1 | 5 | 5 |
| 2 | 1 | 4 | 9 |
| 3 | 1 | 3 | 12 |
| 4 | 2 | 1 | 1 |
| 5 | 2 | 3 | 4 |
| 6 | 2 | 4 | 8 |
| 7 | 2 | 5 | 13 |
| 8 | 3 | 6 | 6 |
| 9 | 3 | 7 | 13 |
| 10 | 1 | 3 | 15 |
| 11 | 1 | 2 | 17 |
------------------------
In above tables foreign key ('pid') Column has values 1 to 3 in different row numbers. I tried to add cost from each 'pid' field name. I havn't found any way to do this,
Can I do that? Can some one help me? am still newbie at sql server
This is a running total problem. You can use SUM OVER() for this.
CREATE TABLE Temp(
id INT,
pid INT,
Cost INT
)
INSERT INTO Temp VALUES
(1, 1, 5), (2, 1, 4), (3, 1, 3),
(4, 2, 1), (5, 2, 3), (6, 2, 4),
(7, 2, 5), (8, 3, 6), (9, 3, 7),
(10, 1, 3), (11, 1, 2);
SELECT
*,
[Sum] = SUM(Cost) OVER(PARTITION BY pid ORDER BY Id)
FROM Temp
ORDER BY id, pid
DROP TABLE TEMP

Resources