Combining multiple tables with same ID - sql

I am trying to combine several tables. The goal is to have them all on one table in the end, but sorted by ID. So if I have a matching ID between some of the tables, it unites into one row based on the ID.
There are more than two tables (I currently have three: table1, table2, table3 but I plan to add more in the future)
Some of the tables don't have the same columns or number of columns.
Some of the tables don't have the same name for the ID column, table1 has "ID" and table2 has it named "identity" and so on...
I try not to include each of all the available columns from every table in the code, because there's a good amount of columns in each of the available tables and I assume adding and naming each one of them in the query would be tiring. I do however know the column name of the ID in each of the tables.
So the column names for the ID are: "ID(table1), Identity(table2), CatalogNum(table3)"
Here's an example,
table1:
**ID** | Name | Price | Date | ....
000212 Rod 200 NULL etc
......
table2:
Descr | **Identitiy** | amount | ...
Silver rod 000212 3 NULL
......
table3:
Type | Price | Condition | **CatalogNum** | .....
Metal NULL 8 000212 etc
Wood 300 1 000313 etc
.....
So end result should look like:
**ID** | Name | Price | Date | Descr | amount | Type | Condition | .... | ... | .....
000212 Rod 200 NULL Silver rod 3 Metal 8 etc NULL etc
000313 NULL 300 NULL NULL NULL Wood 1 NULL NULL etc

is this what you want:
Select b.*, c.*, d.* From
(select ID from table1 union select Identitiy from table2 union select ID from table3)a
left join table1 b on a.ID = b.ID
left join table2 c on a.ID = c.Identitiy
left join table3 d on a.ID = d.ID

Since there's no single source for all of the ID values that could occur in the various tables, you'll have to build one, and then use that to join to all of the other tables to get the columns you're interested in.
For the purposes here, I pulled back all of the columns in all of the tables, though.
WITH IdList AS (
SELECT
ID AS MasterId
FROM table1
UNION
SELECT
Identitiy
FROM table2
UNION
SELECT
CatalogNum
FROM table3
)
SELECT
i.MasterID,
t1.*,
t2.*,
t3.*
FROM IdList as i
LEFT JOIN table1 as t1 ON t1.ID = i.MasterID
LEFT JOIN table2 as t2 ON t2.Identitiy = i.MasterID
LEFT JOIN table3 as t3 ON t3.CatalogNum = i.MasterID;
Result:
+----------+--------+--------+--------+--------+------------+-----------+--------+-------+--------+-----------+------------+
| MasterID | ID | Name | Price | Date | Descr | Identitiy | amount | Type | Price | Condition | CatalogNum |
+----------+--------+--------+--------+--------+------------+-----------+--------+-------+--------+-----------+------------+
| 000212 | 000212 | Rod | 200 | (null) | Silver rod | 000212 | 3 | Metal | (null) | 8 | 000212 |
| 000313 | (null) | (null) | (null) | (null) | (null) | (null) | (null) | Wood | 300 | 1 | 000313 |
+----------+--------+--------+--------+--------+------------+-----------+--------+-------+--------+-----------+------------+
SQL Fiddle demo
EDIT: Your question notes that you want the data in one table, ", but sorted by ID." SQL tables don't work that way. They are, by definition, unordered sets. You impose order on them by using an ORDER BY clause in your SELECT queries. So there is no effort in my query above to create any kind of "order" at all.

Related

Repeat same data based on for each value in another table's column

I have two data tables:
+---------+--------+ +---------+
|Account | Value | | Version |
+---------+--------+ +---------+
| 1 | 10 | | a |
+---------+--------+ +---------+
| 2 | 20 | | b |
+---------+--------+ +---------+
Basically, what I want to do is to add column "version" to the first table and repeat data for each version, e.g:
+---------+--------+---------+
|Account | Value | Version |
+---------+--------+---------+
| 1 | 10 | a |
+---------+--------+---------+
| 2 | 20 | a |
+---------+--------+---------+
| 1 | 10 | b |
+---------+--------+---------+
| 2 | 20 | b |
+---------+--------+---------+
Unfortunately, I can't hard-write the version names since they change very frequently, but data itself is static. Any idea how to do it with SQL?
This sounds like a cross join:
select t1.*, t2.*
from table1 t1 cross join
table2 t2;
This produces a Cartesian product of the two tables -- which is exactly what your question describes.
Note that if either table is empty, this will return no rows.
You can do this in two ways:
First: by executing the below script you will have a table that you desired.
create table yourTableName as
(select t1.*, t2.*
from table1 t1 cross join
table2 t2
)
Second:
Add column version to table1 as nullable
alter table table1 add column version varchar(20)
insert combination data to table1
insert into table1 (Account, Value, Version)
(select t1.*, t2.*
from table1 t1 cross join
table2 t2
)
delete rows that version column is null
delete from table table1 where version is null

How to combine rows and columns?

I have two tables. I need to combine two table.
This First table.
----------------------------
| row_no | Part No |Qty_A |
----------------------------
| 1 | A | 100 |
| 2 | A | 300 |
----------------------------
Second table.
----------------------------
| row_no | Part No |Qty_B |
----------------------------
| 1 | A | 400 |
| 2 | B | 200 |
----------------------------
This is my result:
--------------------------------------
| row_no | Part No | Qty_A | Qty_B |
--------------------------------------
| 1 | A | 100 | 400 |
| 2 | A | 300 | - |
| 2 | B | - | 200 |
--------------------------------------
Two tables was joined by "row_no" and "Part_no" column.
I try to use "LEFT OUTER JOIN" but results not as expected.
SELECT t1.row_no ,t1.part_no ,t1.Qty_A ,t2.Qty_B
FROM
(SELECT 1 as row_no,'A' as part_no,100 as Qty_A) as t1
LEFT OUTER JOIN
(SELECT 1 as row_no, 'B' as part_no,200 as Qty_B) as t2
ON t1.row_no = t2.row_no and t1.part_no = t2.part_no
Sorry for my unclear example.
Update
This is example from a large transaction.
And I need to group it by Part_no and re-arrange by row number like these.
Try below query with union all:
select row_no ,part_no ,Qty_A , '-' as Qty_B from tableA
union all
select row_no ,part_no ,'-' as Qty_A , Qty_B from tableb
or you can try with full outer join:
SELECT t1.row_no ,t1.part_no ,t1.Qty_A ,t2.Qty_B
FROM
(SELECT 1 as row_no,'A' as part_no,100 as Qty_A) as t1
full OUTER JOIN
(SELECT 1 as row_no, 'B' as part_no,200 as Qty_B) as t2
ON t1.row_no = t2.row_no and t1.part_no = t2.part_no
The UNION operator is used to combine the result-set of two or more SELECT statements.
- Each SELECT statement within UNION must have the same number of
columns
- The columns must also have similar data types
- The columns in each SELECT statement must also be in the same order
The first query in the union statement defines the column names.
So in your case you could
select row_no ,part_no ,Qty_A , null as Qty_B from table1
union all
select row_no ,part_no , null, Qty_B from table2

SQL get data that doesn't exist on another table

I'm trying to get a query that get me a data that exist in table1 but not on table2, but has the same id with data table2.
In the following example, I'm trying to get 'SecID-by_Bank' 12456 which shares the same ISIN as another 2 items in table2.
I've tried the following query, but it returned me every data that's not on table2, not just the one that shares the same ISIN.
Query:
SELECT tb1_isin, tb1_SecID_by_Bank
FROM table1
WHERE not EXISTS (
SELECT top 1 null
FROM table2
WHERE table1.tb1_ISIN = table2.tb2_isin
)
Table 1
--------------------------------------------
Row | SecID_by_Bank | Desc | ISIN
--------------------------------------------
1 | 421345 | BlaBla | US1354
--------------------------------------------
499 | 34345 | 2.US | XS1545
--------------------------------------------
500 | 45676 | 2/US | XS1545
--------------------------------------------
501 | 12456 | 2-US | XS1545
--------------------------------------------
Table 2
--------------------------------------------
Row | SecID_by_Bank | Desc | ISIN
--------------------------------------------
1 | 34345 | 2.US | XS1545
--------------------------------------------
2 | 45676 | 2/US | XS1545
Query result needed:
SecID_by_Bank | Desc | ISIN
-------------------------------------
| 12456 | 2-US | XS1545
-------------------------------------
What am I missing?
Thank you!
If you build query in Access try:
SELECT Table1.*
FROM Table1
WHERE (((Table1.[ISIN]) In (SELECT ISIN FROM Table2)) AND ((Table1.SecID_by_Bank) Not In (SELECT SecID_by_BANK FROM Table2)));
Or using 1 subquery:
SELECT Table1.*, Table2.ISIN
FROM Table2 RIGHT JOIN Table1 ON Table2.SecID_by_Bank = Table1.SecID_by_Bank
WHERE (((Table1.ISIN) In (SELECT ISIN FROM Table2)) AND ((Table2.ISIN) Is Null));
For query in SQLServer:
select distinct a.SecID_by_Bank, a.[desc], a.isin from #table1 a left join #table2 b
on a.SecID_by_Bank=b.SecID_by_Bank and a.isin=b.isin
join #table2 c on a.isin=c.isin
where b.isin is null

SQL Query to Bring Back where Row Count is Greater than 1

I have two tables.They have the same data but from different sources. I would like to find all columns from both tables that where id in table 2 occurs more than once in table 1. Another way to look at it is if table2.id occurs only once in table1.id dont bring it back.
I have been thinking it would be some combination of group by and order by clause that can get this done but its not getting the right results. How would you express this in a SQL query?
Table1
| id | info | state | date |
| 1 | 123 | TX | 12-DEC-09 |
| 1 | 123 | NM | 12-DEC-09 |
| 2 | 789 | NY | 14-DEC-09 |
Table2
| id | info | state | date |
| 1 | 789 | TX | 14-DEC-09 |
| 2 | 789 | NY | 14-DEC-09 |
Output
|table2.id| table2.info | table2.state| table2.date|table1.id|table1.info|table1.state|table1.date|
| 1 | 789 | TX | 14-DEC-09 | 1 | 123 | TX | 12-DEC-09 |
| 1 | 789 | TX | 14-DEC-09 || 1 | 123 | NM | 12-DEC-09 |
If you using MSSQL try using a Common Table Expression
WITH cte AS (SELECT T1.ID, COUNT(*) as Num FROM Table1 T1
INNER JOIN Table2 T2 ON T1.ID = T2.ID
GROUP BY T1.ID
HAVING COUNT(*) > 1)
SELECT * FROM cte
INNER JOIN Table1 T1 ON cte.ID = T1.ID
INNER JOIN Table2 T2 ON cte.ID = T2.ID
First, I would suggest adding an auto-incrementing column to your tables to make queries like this much easier to write (you still keep your ID as you have it now for relational-mapping). For example:
Table 1:
TableID int
ID int
Info int
State varchar
Date date
Table 2:
TableID int
ID int
Info int
State varchar
Date date
Then your query would be really easy, no need to group, use CTEs, or row_over partitioning:
SELECT *
FROM Table2 T2
JOIN Table1 T1
ON T2.ID = T1.ID
JOIN Table1 T1Duplicate
ON T2.ID = ID
AND T1.TableID <> T1Duplicate.TableID
It's a lot easier to read. Furthermore, there are lots of scenarios where an auto-incrementing ID field is benefitial.
I find this a much simpler way to do it:
select TableA.*,TableB.*
from TableA
inner join TableB
on TableA.id=TableB.id
where TableA.id in
(select distinct id
from TableA
group by id
having count(*) > 1)

SQL Plus Query - Multiple Table Query

This is causing me more trouble then it should.
I have the following sample tables:
____________________ ____________
| Name| Number | | Number |
|_______|__________| |__________|
| Alice | 1 | | 1 |
| Bob | 2 | | 1 |
|_______|__________| |__________|
I want my result to be:
_____________________________________
| Name | Number | Count(Number) |
|________|___________|_______________|
| Alice | 1 | 2 |
| Bob | 2 | 0 |
|________|___________|_______________|
I'm going back and forward but I'm sure this shouldn't be so tricky. I assume I'm missing something.
I've modified Gordon's answer:
select name, number count(t2.number)
from table1 t1,
table2 t2
where t1.number = t2.number (+)
group by t1.number;
You need a join and aggregation. However, the join needs to be a left outer join to keep all the rows:
select name, number, count(t2.number)
from table1 t1 left outer join
table2 t2
on t1.number = t2.number
group by t1.name, t1.number;
And, the count() is counting the non-NULL values in the second table, so you can get 0 when there is no match.