How to merge two tables to show entries historical changes - sql

I have two tables
T1:
ID
Reference
Status
Event Timestamp
1
Flowers
Dispatched
2021-12-10
2
Flowers
Delivered
2021-12-11
And T2:
ID
Reference
Comments
Event Timestamp
1
Flowers
well done
2021-12-12
2
Flowers
go on
2021-12-13
3
Pot
random
2021-12-13
The table I'm trying to have by querying for Flowers reference is (using Postgres)
t1_ID
t2_ID
Reference
Comments
Status
t1_Event Timestamp
t2_Event Timestamp
1
null
Flowers
null
Dispatched
2021-12-10
null
2
null
Flowers
null
Delivered
2021-12-11
null
null
1
Flowers
well done
Delivered
2021-12-11
2021-12-12
null
2
Flowers
go on
Delivered
2021-12-11
2021-12-13
In other words, I need to have a joined table that records all the update between the two tables.
I tried many queries, like LEFT JOIN, UNION, etc. however all attempts are unsuccessful.
Could you suggest me which SQL statements should I use to obtain the expected result?

Use cte and union
with cte as(
select ID as t1_ID,
null as t2_ID,
Reference,
null as Comments,
Status,
Event_Timestamp as t1_Event_Timestamp,
null as t2_Event_Timestamp,
row_number() over(partition by Reference order by Reference) seq
from t1
)
select t1_id,t2_id,reference,comments,status,t1_event_timestamp,t2_event_timestamp
from cte
union all
select null as t1_ID,
t2.ID::varchar(10) as t2_ID,
t2.Reference,
Comments,
(select max(Status) from cte t3 where t3.seq = (select max(seq) from cte)) as status,
(select max(t1_Event_Timestamp) from cte t3 where t3.Reference = t2.Reference) as t1_Event_Timestamp,
t2.Event_Timestamp as t2_Event_Timestamp
from t1
left join t2 on t1.Reference = t2.Reference
group by t2.ID,t2.Reference,t2.Comments,t2.Event_Timestamp
Demo in db<>fiddle

Related

Using Max with multiple columns from multiple table

I have 3 tables t1=items (items) t2=sales offer catalogue dates
t3=sales offer catalogue item offer price (same item can be included multiple times)
t1
t1id
t1itemcode
1
A001
2
A002
3
A003
4
A004
5
A005
t2
t2id
t2endofferdate
1
2021-02-25
2
2021-03-28
3
2021-02-10
4
2021-04-10
t3
t3id
t3.t1id
t3.t2id
t3.formula
1---
1------
4------
10,80-----
2---
2------
2------
22,00-----
3---
2------
3------
13,00-----
4---
5------
2------
10,00-----
5---
2------
4------
11,25-----
6---
1------
3------
4,50------
I initially needed the itemid and the max(enddate).
I created the following SQL query:
SELECT t1.ID, max(t2.ENDDATE) ENDDATE
FROM t1
LEFT JOIN t3 ON t1.id = t3.t1id
LEFT JOIN t2 ON t3.t2id = t2.id
GROUP BY t1.id
This works fine and the output is OK. Item id not repeated multiple times and in the 2nd col the max date that appears combined with the item from t2 (item) and (t3).
ID ENDDATE
1 -- 2021-04-10
2 -- 2021-04-10
5 -- 2021-03-28
3 -- NULL
4 -- NULL
Now I have to add a col with the formula from t3. I believe that a subquery is needed, but I'm struggling with the syntax. Actually, I need the formula for the certain join of the item (t1) id with the enddate.
The result has to be like this:
ID ENDDATE FORMULA
1 -- 2021-04-10 10,80
2 -- 2021-04-10 11,25
5 -- 2021-03-28 10,00
Appreciate any help.
If you assign a row number based on the ENDDATE and then only take the first row per ID you can pull multiple column values.
WITH cte AS (
SELECT t1.ID, t2.ENDDATE, t3.FORMULA
, ROW_NUMBER() OVER (PARTITION BY t1.ID ORDER BY t2.ENDDATE DESC) RN
FROM t1
LEFT JOIN t3 ON t1.id = t3.t1id
LEFT JOIN t2 ON t3.t2id = t2.id
)
SELECT ID, ENDDATE, FORMULA
FROM cte
WHERE RN = 1;

Selecting max value on subset of data based on other column's value

I'm looking to left join a value from a subset of data from another table, based on a specific value from the first table. Here are example tables:
table1
-----------------
key date
1 2020-01-02
2 2020-03-02
table2
-----------------
key date value
1 2019-12-13 a
1 2019-12-29 b
1 2020-01-14 c
1 2020-02-02 d
2 2019-11-01 e
2 2019-12-02 f
2 2020-04-29 g
Based on the value of date for a specific key value from table1, I want to select the most recent (MAX(date)) from table2, where temp contains all rows for that key value where date is on or before the date from table1.
So, the resulting table would look like this:
key date value
1 2020-01-02 b
2 2020-03-02 f
I'm thinking I could use some type of logic that would create temp tables for each key value where temp.date <= table1.date, then select MAX(temp.date) from the temp table and left join the value. For example, the temp table for key = 1 would be:
date value
1 2019-12-13 a
1 2019-12-29 b
Then it would left join the value b for key = 1, since MAX(date) = 2019-12-29. I'm not sure if this is the right logic to go about my problem; any help would be greatly appreciated!
You can use a correlated subquery:
select t1.*,
(select t2.value
from table2 t2
where t2.key = t1.key and t2.date <= t1.date
order by t2.date desc
fetch first 1 row only
) as value
from table1 t1;
Note that not all databases support the standard fetch first clause. You may need to use limit or select top (1) or something else depending on your database.

SQL conditional join Teradata

I am trying to join the following two tables T1 and T2 on T1.id=T2.id, T1.MonA=T2.MonB such that
Whenever MonA=MonB (iow an entry can be found in both tables),
perform an ordinary join. This is the case for instace for ID A,
MonA=MonB=3
If a MonB entry is in table T2 but no equal MonA entry can be found in
Table T1, the join shall take from table T1 the row where MonA is
maximal. In the sample tables, this is the case for both last rows.
MonA from T1 which are not in T2 shall be ignored
The condition T1.id=T2.id is a necessary precondition, so this always needs to be true!
Table T1
ID MonA Data
A 2 BBB
A 3 CCC
B 4 DDD
B 5 EEE
B 11 EEE
Table T2
ID MonB Organ
A 3 Liver
B 5 Heart
B 7 Kidney
Here is, how the result should look like
ID MonA MonB Data Organ
A 3 3 CCC Liver
B 5 5 EEE Heart
B 11 7 EEE Kidney
I need this to be performed in Teradata SQL and honestly have no idea currently how to tackle the problem. Thanks for help!
EDIT: The may be several entries with identical ID, MonA=MonB, but different Data/Organ columns and i want all of them in the resulting table.
Lets do a join of t1 with t2 as follows
--gets all of the matching records by (id,mona) pairs from t1 with (id,monb) from t2
select a.id,a.mona,b.monb,a.data,b.organ
from t1 a
join t2 b
on a.id=b.id
and a.mona=b.monb
union all /*Here you want only from t2 not there in t1 by id*/
select b.id,x.mona,b.monb,x.data,b.organ
from t2 b
left join t1 a
on a.id=b.id
and a.mona=b.monb
left join (select row_number() over(partition by id order by mona desc) as rnk
,id
,mona
,data
from t1
)x
on b.id=x.id
and x.rnk=1 /*pick up only the largest values arranged by mona*/
where a.mona is null /*Gets only the missing records from t2 which are not in t1*/
This should return the expected result:
SELECT t1.id,t1.mona,t2.monb,t1.data,t2.organ
FROM t1
JOIN t2
ON t1.id=t2.id
QUALIFY
Row_Number()
Over (PARTITION BY t2.id, t2.organ
-- prefer same entry in both tables
ORDER BY CASE WHEN t1.mona = t2.monb THEN 1 ELSE 2 END
-- otherwise take max monA
,t1.mona DESC -- ) = 1

Create View with data (not repeated) from 2 tables with the same structure

In a oracle database, I have 2 tables with the same structure (same columns). One is being migrated to the other. The thing is that I need to create a view that reads records from the 2 tables so that during migration it's possible to read all records. In case there are repeated records, only the ones from table 1 should be displayed in the view.
Table 1
USER_ID START_DATE END_DATE
1 2015-08-12 2015-12-08
2 2015-02-25 2015-06-01
3 2015-04-14 2015-09-21
Table 2
USER_ID START_DATE END_DATE
2 2015-02-25 2015-06-01
4 2015-12-20 2016-01-13
The view should contain the following data:
USER_ID START_DATE END_DATE
1 2015-08-12 2015-12-08
2 2015-02-25 2015-06-01
3 2015-04-14 2015-09-21
4 2015-12-20 2016-01-13
Is this possible?
Thanks!
If when you say repeated records you mean that all 3 columns are the same, than I don't understand why you want them from table a since they are the same.
In addition, you can just create view as:
select * from table1
union
select * from table2
that will eliminate all duplicates and basically will keep those from table1 since its the first table(although it doesn't matter)
If you are stubborn on doing it like you said maybe because not all the columns needs to be the same.
then what you need is a full outer join
SELECT case when a.id is not null then a.id else b.id end as id,
case when a.id is not null then a.start_date else b.start_date end as start_date,
case when a.id is not null then a.end_date else b.end_date as end_Date
from table a full outer join table2 b on (a.id = b.id)
This is the answer I was looking for, less verbose than the answer from sagi
select *
from table1
union all
select *
from table2 a
where not exists (select null from table1 where user_id = a.user_id);

Mix records of two different tables

I'm looking for a way to solve my SQL problem.
I have 2 tables in Firebird 2.5 ( T1 and T2 ) like these:
T1 (
T1_ID INTEGER,
T1_DAY DATE,
T1_NAME VARCHAR(200)
)
T2 (
T2_ID INTEGER,
T2_DAY DATE,
T2_NAME VARCHAR(200)
)
I need a query that mixes records of those tables and sort them in ascending date order. I don't care if a join query increases the number of fields or the date field is not the same as result or stored procedures are needed.
Example output
T1_ID T1_DAY T1_NAME T2_ID T2_DAY T2_NAME
---------------------------------------------------
1 01/02/2011 BOB NULL NULL NULL
2 27/02/2011 SAM NULL NULL NULL
NULL NULL NULL 8 15/03/2011 PETER
NULL NULL NULL 10 21/03/2011 JOHN
6 17/04/2011 AMY NULL NULL NULL
or (better output)
ID DAY NAME
-------------------------
1 01/02/2011 BOB
2 27/02/2011 SAM
8 15/03/2011 PETER
10 21/03/2011 JOHN
6 17/04/2011 AMY
You want the UNION operator:
SELECT
T1.T1_ID ID,
T1.T1_DAY DAY,
T1.T1_NAME NAME
FROM
T1
UNION
SELECT
T2.T2_ID,
T2.T2_DAY
T2.T2_NAME
FROM
T2
;
You can make the individual selects have any additional features you like. The only restriction is that all of the columns in both of the select lists are in the same order and have the same type (they are "union compatible"). The resulting rows will have column headings like the first select.
edit: To control the ordering of a union, you'll have to do the union in a subselect and the ordering in the outer query.
SELECT u.ID, u.DAY, u.NAME
FROM (
SELECT T1.T1_ID ID, T1.T1_DAY DAY, T1.T1_NAME NAME
FROM T1
UNION
SELECT T2.T2_ID, T2.T2_DAY T2.T2_NAME
FROM T2
) u
ORDER BY u.NAME;