SQL update query on join table - sql

UPDATE
t1
SET
t1.c3 = t2.c3,
t1.c4 = t1.c4
FROM
t1
LEFT JOIN t2 ON t1.c1 = t2.c1 AND t1.c2 = t2.c2
WHERE
t1.c5 = 'In Progrss'
I want to update value from top row of table t2.
For example in t2 table having 3 rows with criteria match above only top row value update in t1 table(ROW ID 3 VALUES TO UPDATE IN t1 table).
t2 table:
id c1 c2 c3 c4
-----------------------------
1 ABC XYZ 280 300
2 ABC XYZ 290 400
3 ABC XYZ 310 500
4 PQR STR 210 400
t1 table:
id c1 c2 c3 c4 c5
----------------------------------
1 ABC XYZ In Progrss
5 ABC XYZ In Progrss
8 ABC XYZ In Progrss
15 PQR STR IN Progress

Postgres’ update/join syntax goes like:
update t1
set c3 = t2.c3, c4 = t1.c4
from t2
where
t1.c1 = t2.c1
and t1.c2 = t2.c2
and t1.c5 = 'In Progress'
If there are several matching rows in t2 and you want the one with the smallest id, then you can use row_number() in a subquery:
update t1
set c3 = t2.c3, c4 = t1.c4
from (select t2.*, row_number() over(partition by c1, c2 order by id) rn from t2) t2
where
t1.c1 = t2.c1
and t1.c2 = t2.c2
and t1.c5 = 'In Progress'
and t2.rn = 1

Related

select a value from different table based on conditions in sql

I'm trying to select a value from a different table based on current table values and condition
Table 1:
C1
C2
C3
1
2
3
1
4
5
1
6
6
2
3
3
Table 2:
D1
D2
D3
D4
1
2
3
Value1
1
4
5
Value2
1
6
8
Value3
2
3
4
Value4
2
Value5
And Im trying to get the below expected result table a single line sql
Results:
C1
C2
C3
D4
1
2
3
Value1
1
4
5
Value2
1
6
6
2
3
3
Value5
The condition is to pick D4 value only
(C1=D1 and C2=D2 and C3=D3) matches then D4 or when C1=D1 matches then D4 else null for all
I tried inner join and also case statement but no success
Here is the fiddle i had created
This looks like a left join:
select t1.*, t2.d4
from table1 t1 left join
table2 t2
on t1.C1 = t2.D1 and
(t1.C2 = t2.D2 or t2.D2 is null) and
(t1.C3 = t2.D3 or t2.D3 is null);
Note: It is a little hard to tell from the explanation if you need for both D2 and D3 to be NULL. If so:
select t1.*, t2.d4
from table1 t1 left join
table2 t2
on t1.C1 = t2.D1 and
(t1.C2 = t2.D2 and t1.C3 = t2.D3 or
t2.D2 is null and t2.D3 is null
);
Here is the fiddle.

Update the changed row of target table only using source table if there is any value mismatch between 2 columns

Table T1
ID C1 C2 C3
-- -- -- --
1 x y z
2 p q r
3 a b c
Table T2
1 x y z
2 p q1 r
3 a b c1
Need to update all values of T2 into T1 to ensure both table should have same value.This can be achieved by merge statement.But in table T1 has a column update_timestamp which will update only if there is any mismatch between 2 table.In merge the update_timestamp updates if there is no mismatch also.In above example the update_timestamp column update for ID no 2 & 3 only.
MERGE INTO T1
USING T2
ON (T1.ID = T2.ID)
WHEN MATCHED THEN
UPDATE SET T1.C1 = T2.C1,T1.C2 = T2.C2,T1.C3 = T2.C3,T1.update_timestamp=SYSDATE;
Try this one (in case you track the changes for all 3 columns - c1, c2 and c3):
MERGE INTO T1
USING (
select id, c1, c2, c3 from T2
minus
select id, c1, c2, c3 from T1
) T2
ON (T1.ID = T2.ID)
WHEN MATCHED THEN
UPDATE SET T1.C1 = T2.C1,T1.C2 = T2.C2,T1.C3 = T2.C3,T1.update_timestamp=SYSDATE;

Incorrect result when use same alias name in HiveQL

We have encountered a weird problem, which Hive returned incorrect result while use same alias name in subquery.
Following 3 SQL will return "A, C":
SELECT * FROM
(
SELECT T1.C1, T2.C1 C2
FROM (SELECT 'A' C1) T1
LEFT JOIN (SELECT 'C' C1) T2 ON 1 = 1
WHERE T1.C1 = 'C') T1
SELECT * FROM (SELECT T1.C1, T2.C1 C2 FROM (SELECT 'A' C1) T1 LEFT JOIN (SELECT 'C' C1) T2 ON 1 = 1 WHERE T1.C1 = 'C') T2
SELECT * FROM (SELECT T1.C1, T2.C1 C2 FROM (SELECT 'A' C1) T1 LEFT JOIN (SELECT 'C' C1) T2 ON 1 = 1 WHERE T2.C1 = 'C') T1
Following 1 SQL will return "C, C":
SELECT * FROM (SELECT T1.C1, T2.C1 C2 FROM (SELECT 'A' C1) T1 LEFT JOIN (SELECT 'C' C1) T2 ON 1 = 1 WHERE T2.C1 = 'C') T2

SQL Query - Indirect joining of two tables

I have two tables like the following
Table1
COL1 COL2 COL3
A 10 ABC
A 11 ABC
A 1 DEF
A 2 DEF
B 10 ABC
B 11 ABC
B 1 DEF
C 3 DEF
C 12 ABC
C 21 GHI
Table2
COL1 GHI ABC DEF
A1 21 10 1
A2 21 12 1
A3 21 10 1
A4 23 10 1
A5 25 11 3
A6 21 14 3
A7 25 11 1
A8 23 10 1
A9 29 10 2
A10 21 12 3
I have created another temporary table that returns all the distinct values from tbl1.col1
The values of col3 in tbl1 are columns in tbl2, which are populated by some values.
What I need is for each of these distinct values of table1.column1, (A, B, C) in this case, return a combination of table2.column1 and table1.column1 such that
the ABC value of table2.column1 matches any of the ABC value of the "group" from table1,
AND the DEF value of table2.column1 matches any of the DEF value of the "group" from table1,
AND IF THE GROUP CONTAINS GHI VALUES, the GHI value of table2.column1 matches any of the GHI value of the "group" from table1
So, I would need something like the following
Output Table
Table2.COL1 Table1.Col1
A1 A
A3 A
A4 A
A7 A
A8 A
A9 A
A1 B
A3 B
A4 B
A7 B
A8 B
A10 C
I tried something like this, but Im not sure if this is the right way of approaching
select table2.col1, temp_distinct_table.column1
from table2, temp_distinct_table
where table2.def IN (SELECT col2
FROM table1
WHERE table1.col1 = temp_distinct_table.col1
AND table1.col3 = 'DEF')
AND table2.abc IN (SELECT col2
FROM table1
WHERE table1.col1 = temp_distinct_table.col1
AND table1.col3 = 'ABC')
AND (
table2.ghi IN (SELECT col2
FROM table1
WHERE table1.col1 = temp_distinct_table.col1
AND table1.col3 = 'GHI')
OR NOT EXISTS (SELECT col2
FROM table1
WHERE table1.col1 = temp_distinct_table.col1
AND table1.col3 = 'GHI')
)
where temp_distinct_table contains of all the distinct values from table1.col1
Could someone guide me on the matter?
Another approach, counting how many matches there are for each t1.col/t2.col combination after joining all the possible matches:
select distinct t2_col1, t1_col1
from (
select t2.col1 as t2_col1, t1.col1 as t1_col1, t1.ghi_count as t1_ghi_count,
count(case when t1.col3 = 'ABC' then 1 end)
over (partition by t1.col1, t2.col1) as abc_matches,
count(case when t1.col3 = 'DEF' then 1 end)
over (partition by t1.col1, t2.col1) as def_matches,
count(case when t1.col3 = 'GHI' then 1 end)
over (partition by t1.col1, t2.col1) as ghi_matches
from (
select t1.*,
count(case when t1.col3 = 'GHI' then 1 end)
over (partition by t1.col1) as ghi_count
from table1 t1
) t1
join table2 t2
on (t1.col3 = 'ABC' and t2.abc = t1.col2)
or (t1.col3 = 'DEF' and t2.def = t1.col2)
or (t1.col3 = 'GHI' and t2.ghi = t1.col2)
)
where abc_matches > 0
and def_matches > 0
and (t1_ghi_count = 0 or ghi_matches > 0)
order by t1_col1, t2_col1;
Which with your sample data gets:
T2_COL T1_COL
------ ------
A1 A
A3 A
A4 A
A7 A
A8 A
A9 A
A1 B
A3 B
A4 B
A7 B
A8 B
A10 C
Not sure if the efficiency of that will be significantly different to MTO's cross join with your real data.
This becomes quite simple when you use collections (and you only need to do one table scan for each table):
Oracle Setup:
CREATE TYPE intlist AS TABLE OF INT;
/
Query:
SELECT t2.col1 AS t2_col1,
t1.col1 AS t1_col1
FROM (
SELECT col1,
CAST( COLLECT( CASE col3 WHEN 'ABC' THEN col2 END ) AS INTLIST ) AS abc,
CAST( COLLECT( CASE col3 WHEN 'DEF' THEN col2 END ) AS INTLIST ) AS def,
CAST( COLLECT( CASE col3 WHEN 'GHI' THEN col2 END ) AS INTLIST ) AS ghi
FROM table1
GROUP BY col1
) t1
INNER JOIN table2 t2
ON ( t2.abc MEMBER OF t1.abc
AND t2.def MEMBER OF t1.def
AND ( t2.ghi MEMBER OF t1.ghi OR t1.ghi IS EMPTY ) );
Output:
t2_col1 t1_col1
------- -------
A1 A
A3 A
A4 A
A7 A
A8 A
A9 A
A1 B
A3 B
A4 B
A7 B
A8 B
A10 C
Update
An alternative query without using collections (it is going to be more efficient than your query but probably less efficient than collections):
SELECT t2.col1,
t1.col1
FROM table1 t1
CROSS JOIN
table2 t2
GROUP BY t1.col1, t2.col1
HAVING COUNT( CASE WHEN t1.col2 = t2.abc AND t1.col3 = 'ABC' THEN 1 END ) > 0
AND COUNT( CASE WHEN t1.col2 = t2.def AND t1.col3 = 'DEF' THEN 1 END ) > 0
AND ( COUNT( CASE WHEN t1.col2 = t2.ghi AND t1.col3 = 'GHI' THEN 1 END ) > 0
OR COUNT( CASE t1.col3 WHEN 'GHI' THEN 1 END ) = 0 )
ORDER BY t1.col1, t2.col1;
Update 2:
Changed from CROSS JOIN to INNER JOIN:
SELECT t2.col1 AS t2_col1,
t1.col1 AS t1_col1
FROM (
SELECT t1.*,
COUNT( CASE col3 WHEN 'GHI' THEN 1 END )
OVER ( PARTITION BY col1 ) AS has_ghi
FROM table1 t1
) t1
INNER JOIN table2 t2
ON ( t1.col3 = 'ABC' AND t2.abc = t1.col2 )
OR ( t1.col3 = 'DEF' AND t2.def = t1.col2 )
OR ( t1.col3 = 'GHI' AND t2.ghi = t1.col2 )
GROUP BY t1.col1, t2.col1, t1.has_ghi
HAVING COUNT( CASE t1.col3 WHEN 'ABC' THEN 1 END ) > 0
AND COUNT( CASE t1.col3 WHEN 'DEF' THEN 1 END ) > 0
AND ( COUNT( CASE t1.col3 WHEN 'GHI' THEN 1 END ) > 0 OR has_ghi = 0 )
ORDER BY t1.col1, t2.col1;

How to make this Sql Consult

I have two tables:
T1
C1 C2 (Columns)
A 1
B 2
T2
C1 C2 (Columns)
A Null
C Null
what I expect as result is:
C1 C2 (Columns)
A 1
B 2
C NULL
please help, I try to find the most clean solution, thanks.
I do this:
Select case when T1.C1 is Null then T2.C1 else T1.C1 end As C1,
T1.C2
from T1 FULL OUTER JOIN T2 on T1.C1 = T2.C1