Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Merging two version-tracking tables while filling in values

Tags:

sql

postgresql

I have two history tables that track changes in database values, using a revision id to track the individual changes. e.g.

Table 1:

 rev |  A   |  B 
=================
 1   |  100 | 'A'
 4   |  150 | 'A'
 7   |  100 | 'Z'

Table 2:

 rev |  C   |  D 
==================
 1   |  200 | True
 5   |    0 | True
 8   |    0 | False

The goal would be to merge the two tables into:

 rev |  A   |  B  |  C  |  D 
===============================
 1   |  100 | 'A' | 200 | True
 4   |  150 | 'A' | 200 | True
 5   |  150 | 'A' |   0 | True
 7   |  100 | 'Z' |   0 | True
 8   |  100 | 'Z' |   0 | False

The idea being that for for a given revision, I would take the values corresponding to that revision or the highest revision less than it.

The SQL query that comes to mind would be something akin to cross joining the two tables with constraint rev1 < rev2, then selecting rows using a subquery where rev1 = max(rev1) for each given rev2; unioning this query with its counterpart exchanging rev2 and rev1; and finally filtering out duplicates from where rev1 = rev2.

The questions are:

  • Is there a name for this type of join?
  • Is there an idiom for performing this type of join in SQL, or would it be better to do it programmatically (which would definitely be much simpler and possibly more efficient)?
like image 751
Nan L Avatar asked Oct 19 '12 22:10

Nan L


People also ask

How do you join two tables without losing info?

To join two tables based on a column match without loosing any of the data from the left table, you would use a LEFT OUTER JOIN. Left outer joins are used when you want to get all the values from one table but only the records that match the left table from the right table.

What can you use to combine data from two or more tables into a single result set?

Sometimes you might want to list the records from one table or query with those from one or more other tables to form one set of records - a list with all the records from the two or more tables. This is the purpose of a union query in Access.


2 Answers

SQL Fiddle

select
    coalesce(t1.rev, t2.rev) rev,
    coalesce(a, lag(a, 1) over(order by coalesce(t2.rev, t1.rev))) a,
    coalesce(b, lag(b, 1) over(order by coalesce(t2.rev, t1.rev))) b,
    coalesce(c, lag(c, 1) over(order by coalesce(t1.rev, t2.rev))) c,
    coalesce(d, lag(d, 1) over(order by coalesce(t1.rev, t2.rev))) d
from
    t1
    full join
    t2 on t1.rev = t2.rev
order by rev
like image 96
Clodoaldo Neto Avatar answered Sep 28 '22 09:09

Clodoaldo Neto


This can be achieved by sub queries

SELECT ISNULL(Table1.rev,Table2.rev) AS rev
,ISNULL(A,(SELECT TOP 1 A FROM Table1 AS T1 WHERE ISNULL(Table1.rev,Table2.rev) > T1.rev AND A IS NOT NULL ORDER BY rev DESC)) AS A
,ISNULL(B,(SELECT TOP 1 B FROM Table1 AS T1 WHERE ISNULL(Table1.rev,Table2.rev) > T1.rev AND B IS NOT NULL ORDER BY rev DESC)) AS B
,ISNULL(C,(SELECT TOP 1 C FROM Table2 AS T2 WHERE ISNULL(Table1.rev,Table2.rev) > T2.rev AND C IS NOT NULL ORDER BY rev DESC)) AS C
,ISNULL(D,(SELECT TOP 1 D FROM Table2 AS T2 WHERE ISNULL(Table1.rev,Table2.rev) > T2.rev AND D IS NOT NULL ORDER BY rev DESC)) AS D
FROM Table1
FULL OUTER JOIN Table2
ON Table1.rev = Table2.rev
like image 25
Prasanna Avatar answered Sep 28 '22 08:09

Prasanna