How to update rows based on one field/column of snowflake tables - snowflake-cloud-data-platform

I want to update one table using another table on field "Id" such that it wont create duplicates
let say my first table is Table1 and second table is Table2 . I would like to update the row in Table1 from Table2 when the Id is matching
I am aware of using UNION function but this applies to entire columns where I only need to consider a single column.
https://docs.snowflake.com/en/sql-reference/operators-query.html#union-all
Example of my Tables
Table1
Id name number value
1 a 8 100
2 b 8 100
3 c 8 100
4 d 8 100
Table2
Id name number value
3 c 8 99
4 d 6 100
5 e 7 100
Expected output
Id name number value
1 a 8 100
2 b 8 100
3 c 8 99
4 d 6 100
5 e 7 100
Please note that in the output table row with Id 3,4 has be updated and new Id 5 is inserted. Can someone help me with the select query to get the desired output?

You can use MERGE command:
merge into table1 using table2 on table1.id = table2.id
when matched then
update set table1.name = table2.name, table1.number = table2.number, table1.value = table2.value
when not matched then
insert (Id,name,number,value) values (table2.id, table2.name, table2.number, table2.value);
select * from table1;
+----+------+--------+-------+
| ID | NAME | NUMBER | VALUE |
+----+------+--------+-------+
| 5 | e | 7 | 100 |
| 1 | a | 8 | 100 |
| 2 | b | 8 | 100 |
| 3 | c | 8 | 99 |
| 4 | d | 6 | 100 |
+----+------+--------+-------+
https://docs.snowflake.com/en/sql-reference/sql/merge.html
If you don't want to update the table, you may use IFNULL and full outer join:
select
IFNULL( t1.id, t2.id) id,
IFNULL( t2.name, t1.name ) name,
IFNULL( t2.number, t1.number ) number,
IFNULL( t2.value, t1.value ) value
from table1 t1
full join table2 t2
on t1.id = t2.id;
+----+------+--------+-------+
| ID | NAME | NUMBER | VALUE |
+----+------+--------+-------+
| 1 | a | 8 | 100 |
| 2 | b | 8 | 100 |
| 3 | c | 8 | 99 |
| 4 | d | 6 | 100 |
| 5 | e | 7 | 100 |
+----+------+--------+-------+

Related

DELETE TOP variable records with variable from grouping of another table

Say I have two tables: A and B
Table A
+----+-------+
| id | value |
+----+-------+
| 1 | 20 |
| 2 | 20 |
| 3 | 10 |
| 4 | 0 |
+----+-------+
Table B
+----+-------+
| id | value |
+----+-------+
| 1 | 20 |
| 2 | 10 |
| 3 | 30 |
| 4 | 20 |
| 5 | 20 |
| 6 | 10 |
+----+-------+
If I do SELECT value, COUNT(*) AS occurrence FROM A GROUP BY value, I'll get:
+-------+------------+
| value | occurrence |
+-------+------------+
| 20 | 2 |
| 10 | 1 |
| 0 | 1 |
+-------+------------+
Based on this grouping of table A, I want to delete occurrence records from table B with the same values. In other words, I want to delete from B 2 records with value 20, 1 record with value 10, and 1 record with value 0. (Other conditions include 'do nothing if no record exists' and 'smallest id first', but I think these conditions are pretty trivial compared to the bulk of this question.)
Table B after deleting should be:
+----+-------+
| id | value |
+----+-------+
| 3 | 30 |
| 5 | 20 |
| 6 | 10 |
+----+-------+
From the official TOP documentation, doesn't seems like I can perform some JOIN to use as the TOP expression.
We could use ROW_NUMBER with CTEs here:
WITH cteA AS (
SELECT value, COUNT(*) cnt
FROM A
GROUP BY value
),
cteB AS (
SELECT *, ROW_NUMBER() OVER (PARTITION BY value ORDER BY id) rn
FROM B
)
DELETE
FROM cteB b
INNER JOIN cteA a
ON b.value = a.value
WHERE
b.rn <= a.cnt;
The logic here is that we use ROW_NUMBER to keep track of the order of each value in the B table. Then, we join to bring in the counts of each value in the A table, and we only delete B records for which the row number is strictly less than or equal to the A count.
See the demo link below to verify that the logic be correct. Note that I use a select there, not a delete, but the correct rows are being targeted for deletion.
Demo

SQL Server - Need to create multiple rows based on lookup value

How do I create multiple rows in a new table based on a common value in another table?
ProviderTable: PersonTable:
-------------------- ---------------------
ProviderID | GroupID PersonID | ProviderID
1 | A 100 | 1
2 | A 101 | 3
3 | A 102 | 8
4 | NULL 103 | 10
5 | B 104 | 5
6 | C 105 | 4
7 | B
8 | NULL
9 | NULL
10 | C
ProviderTable.ProviderID = PersonTable.ProviderID
I need to create a new table with a person row for each provider where Provider.GroupID=Provider.GroupID
Results I am looking for:
New-table:
PersonID | ProviderID
100 | 1
100 | 2
100 | 3
101 | 3
101 | 1
101 | 2
102 | 8
103 | 10
103 | 6
104 | 5
104 | 7
105 | 4
This quick version gets the sort order you are looking for. Test data is included:
DECLARE #pt table (
ProviderId int,
GroupId varchar(2)
)
DECLARE #pet table (
PersonId int,
ProviderId int
)
INSERT INTO #pt Values
(1,'A'),
(2,'A'),
(3,'A'),
(4,NULL),
(5,'B'),
(6,'C'),
(7,'B'),
(8,NULL),
(9,NULL),
(10,'C')
INSERT INTO #pet VALUES
(100,1),
(101,3),
(102,8),
(103,10),
(104,5),
(105,4)
SELECT pe.PersonId,
IsNull(p2.ProviderId, p1.providerId) As ProviderId
FROM #pt p1
INNER JOIN #pet pe
ON p1.ProviderId = pe.ProviderId
LEFT JOIN #pt p2
ON p1.GroupId = p2.GroupId
ORDER BY pe.personId,
CASE
WHEN pe.ProviderId = p2.ProviderId
Then 0
ELSE 1
END
You can use the following SQL-statement:
SELECT PER.PersonID, COALESCE(PG.ProviderID, PP.ProviderID) AS ProviederID
FROM PersonTable PER
INNER JOIN ProviderTable PP
ON PP.ProviderID = PER.ProviderID
LEFT OUTER JOIN ProviderTable PG
ON PG.GroupID = PP.GroupID;

How to get value conditionally from another row in sub table

Select * from LoanAccount main INNER JOIN LoanSubAccount sub
WHERE main.LoanAccountID = sub.LoanAccountID
AND sub.LoanStatus = 4
My objective is to retrieve rows with LoanStatus = 4 but replace the amount with records with LoanStatus = 2.
End result expected to be
WITH cte AS (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY LoanAccountID, LoanStatus
ORDER BY LoanSubAccountID) rn
FROM LoanSubAccount
)
SELECT t1.LoanSubAccountID,
t1.LoanAccountID,
t1.LoanStatus,
t1.CommodityType,
t2.Amount
FROM cte t1
INNER JOIN cte t2
ON t1.rn = t2.rn AND
t1.LoanStatus > t2.LoanStatus
Rather than giving a verbose explanation, I would rather show a table representing what the above CTE would look like:
rn | LoanSubAccountID | LoanAccountID | LoanStatus | CommodityType | Amount
1 | 1 | 1 | 2 | 1 | 100
2 | 2 | 1 | 2 | 2 | 200
1 | 3 | 1 | 4 | 3 | 150
2 | 4 | 1 | 4 | 4 | 150
If I read your requirement correctly, you want to connect rows having the same row number from the two different loan statuses. The join query I gave above does this.

Swap row values in SQL Server

I have question about SQL Server
Source: emp
id | name | check |deptname
100 | a | 1 |ceo
100 | b | 2 |hr
100 | c | 3 |po
100 | d | 5 |no
101 | a | 1 |pm
101 | b | 5 |ceo
102 | a | 1 |rn
102 | b | 2 |han
Here same id have check 2 and 5 values then we need to replace check values to 2 check values for that id.
Based on above table I want load/output data into target table like below
Target : emp1
id | name | check |deptname
100 | a | 1 |ceo
100 | d | 2 |hr
100 | c | 3 |po
101 | a | 1 |pm
101 | b | 5 |ceo
102 | a | 1 |rn
102 | b | 2 |han
and I tried like below
select
a1.id,
a1.name,
isnull(a2.[check],a1.[check]) as [check]
from
emp as a1
left outer join
emp as a2 on a2.id = a1.id
and a1.[check] in (2,5)
and a2.[check] in (2,5)
and a2.[check] <> a1.[check]
where
a2.id is null
or (a1.[check] = 5
and a2.[check] = 2)
That query does not return the right result.
Please tell me how to write query to get the expected output in SQL Server
This is how you can do that:
select
e1.id,
isnull(e2.name, e1.name) as name,
e1.[check],
e1.deptname
from emp e1
left outer join emp e2
on e2.id = e1.id and e1.[check] = 2 and e2.[check] = 5
where
not exists (select 1 from emp e3 where e3.id = e1.id and
e1.[check] = 5 and e3.[check] = 2)
Example in SQL Fiddle

Sql server join by group?

I have this table :
id | type | date
1 | a | 01/1/2012
2 | b | 01/1/2012
3 | b | 01/2/2012
4 | b | 01/3/2012
5 | a | 01/5/2012
6 | b | 01/5/2012
7 | b | 01/9/2012
8 | a | 01/10/2012
The POV is per date. if 2 rows contains the same date , so both will visible in the same line ( left join).
Same date can be shared by 2 rows max.
so this situation can't be :
1 | a | 01/1/2012
2 | b | 01/1/2012
3 | a | 01/1/2012
if in the same date there is group a and b show both of them in single line using left join
if in date there is only a group , show it as single line ( +null at the right side )
if in date there is only b group , show it as single line ( +null at the left side )
Desired result :
Date |typeA|typeB |a'id|b'id
01/1/2012 | a | b | 1 | 2
01/2/2012 | | b | | 3
01/3/2012 | | b | | 4
01/5/2012 | a | b | 5 | 6
01/9/2012 | | b | | 7
01/10/2012 | a | | 8 |
I know this suppose to be simple , but the main anchor of join here is the date.
The problem I've encountered is when I read line 1 , i search in the table all rows with the same date...fine. - its ok.
But when I read the second line , I do it also , and it yields the first row - which already was counted...
any help ?
here is the sql fiddle :
https://data.stackexchange.com/stackoverflow/query/edit/82605
I think you want a pivot
select
[date],
case when [a] IS null then null else 'a' end typea,
case when [b] IS null then null else 'b' end typeb,
a as aid,
b as bid
from yourtable src
pivot (max(id) for type in ([a],[b]))p
If you want to do it with joins..
select ISNULL(a.date, b.date), a.type,b.type, a.id,b.id
from
(select * from yourtable where type='a') a
full outer join
(select * from yourtable where type='b') b
on a.date = b.date

Resources