SQL merge results from multiple joined tables into a single view field (without union) - sql

Is there a way to merge/combine the results from multiple joined tables into a single field?
Two key details:
Must not use a Union.
Must be able to generate a View with the code.
We have a nested table structure and there's quite a bit of conditional logic, so I'd like to avoid writing the same large query multiple times (hence why I'm trying to avoid a Union).
select [Combine Id results from all 4 tables]
from Table1 tbl1
inner join Table2 tbl2 on tbl1.Id = tbl2.ParentId
inner join Table3 tbl3 on tbl2.Id = tbl3.ParentId
inner join Table4 tbl4 on tbl3.Id = tbl4.ParentId
So if the tables contain the following data:
Table 1
Id, ParentId
1, 1
Table 2
Id, ParentId
2, 1
Table 3
Id, ParentId
3, 2
Table 4
Id, ParentId
4, 3
Is it possible to produce the following single-field output (list of integers) using the join structure from my original query?:
Id
1
2
3
4

I think apply does what you want:
select v.id
from Table1 tbl1 inner join
Table2 tbl2
on tbl1.Id = tbl2.ParentId inner join
Table3 tbl3
on tbl2.Id = tbl3.ParentId inner join
Table4 tbl4
on tbl3.Id = tbl4.ParentId cross apply
(values (tbl1.id), (tbl2.id), (tbl3.id), (tbl4.id)) v(id);

Related

SQL Server : removing duplicate column while joining tables

I have 4 tables with one column is common on all tables. Is there a way to create a view where I can join all tables by same column where I see the common column only once.
Let's say I have table1
Cust ID | Order ID | Product_Name
Table2
Cust_ID | Cust_Name | Cust_Address
Table3
Cust_ID | Cust_Acc | Acc_Type
Table4
Cust_ID | Contact_Phone | Cust_Total_Ord
Here is the code I use to join tables;
SELECT *
FROM table1
LEFT JOIN table2 ON table1.Cust_ID = table2.Cust_ID
LEFT JOIN table3 ON table2.Cust_ID = table3.Cust_ID
LEFT JOIN table4 ON table3.Cust_ID = table4.Cust_ID
I get all tables joined by I see Cust_ID from each table as below;
Cust ID| Order ID|Product_Name| Cust_ID| Cust_Name|Cust_Address| Cust_ID| Cust_Acc| Acc_Type|Cust_ID|Contact_Phone|Cust_Total_Ord
Is there a way to remove duplicate Cust_ID columns or do I need to write each column name in the SELECT? I have more than 50 columns in total so will be difficult to write all.
Sorry if it is a really dumb question, I have checked previous similar questions but couldn't figure out and thanks for help.
you have common columns on all tables so could use using(common_column) to remove duplicated columns.
SELECT *
FROM table1
LEFT JOIN table2 using(Cust_ID)
LEFT JOIN table3 using(Cust_ID)
LEFT JOIN table4 using(Cust_ID)
I hop that useful.
you need to select columns from three tables first and then make inner join like below
select
t1.cust_id, t1.col1, t1.col2,
t2.col1_table2, t2.col2_table2,
t3.col1_table3, t3.col2_table3
from
table1 t1
inner join
table2 t2 on t1.cust_id = t2.cust_id
join table3 t3 on t1.cust_id = t3.cust_id
Result as shown in below image
No, you cannot easily do what you want in SQL Server. In other databases, you can use the using clause.
One thing you can do is select the columns explicitly from all but the first table:
SELECT t1.*, . . .
FROM table1 t1 LEFT JOIN
table2 t2
ON t1.Cust_ID = t2.Cust_ID LEFT JOIN
table3
ON t1.Cust_ID = table3.Cust_ID LEFT JOIN
table4
ON t1.Cust_ID = table4.Cust_ID;
Perhaps more important than the column issue, I changed the join conditions. You are using LEFT JOIN, so the first table is the "driving" table. When you say t2.Cust_ID = t3.Cust_Id, this returns true only when there was a match to table2. In general, you want to use the columns from table1, because it is the first one in the chain of LEFT JOINs.

SQL joining 4 tables issue

I have four tables:
T1
ID ID1 TITLE
1 100 TITLE1
2 100 TITLE2
3 100 TITLE3
T2
ID TEXT
1 LONG1
2 LONG2
T3
ID1 ID2
100 200
T4
ID4 ID2 SUBJECT
1 200 A
2 200 B
3 200 C
4 200 D
5 200 E
I want output in this result format:
TITLE TEXT SUBJECT
TITLE1 LONG1 A
TITLE2 LONG2 B
TITLE3 null C
null null D
null null E
So I made this query but it gives me much more results than it should be.On example titles asre displayed more times than just once etc.
SELECT
t1.title,
t2.text,
t4.subject
FROM t1
LEFT OUTER JOIN t2 ON t1.id=t2.id
INNER JOIN t3 ON t1.id1=t3.id1
LEFT OUTER JOIN t4 ON t4.id2=t3.id2
WHERE
t1.id1=100
Thanks for help
Disclaimer: I don't work with DB2. After some browsing through documentation I have found that DB2 supports row_number() and full outer join, but I might easily be wrong.
To get rid of n:m relationship one has to build additional key. In this case simple solution is to add row number to each record in t1 and t4 and use it as join condition. Row_number does just that, produces numbers for groups of data defined by partition by in ascending sequence in order defined by order by.
As there is difference in number of records in t1 and t4, and it is unknown which one always has more records, I use full outer join to join them.
You can see the test (Sql Server version) # Sql Fiddle.
select t1_rn.title,
t2.[text],
t4_rn.subject
from
(
select t1.id,
t1.title,
t1.id1,
t3.id2,
row_number() over(partition by t1.id1
order by id) rn
from t1
inner join t3
on t1.id1 = t3.id1
) t1_rn
full outer join
(
select t4.subject,
t3.id1,
t4.id2,
row_number() over(partition by t4.id2
order by id4) rn
from t4
inner join t3
on t4.id2 = t3.id2
) t4_rn
on t1_rn.id1 = t4_rn.id1
and t1_rn.id2 = t4_rn.id2
and t1_rn.rn = t4_rn.rn
left join t2
on t1_rn.id = t2.id
This kind of work should definitely be done on presentation side of an application, but I believe that software you are using requires already prepared data.
try this :
select t1.title,t2.text,t4.subject
from t4
left join t3
on t4.id2=t3.id2
left join t1
on t1.id1=t3.id1
left join t2
on t1.id=t2.id
where t1.id=100
You should change your tables. Your last join does that to your output -just analyze your query. for every record from T1 you have every record from T4.
Outer joins are guaranteed to replicate rows, instead of matching only the ones you need. You may want to look at this:
http://blog.sqlauthority.com/2009/04/13/sql-server-introduction-to-joins-basic-of-joins/
To understand what the join types are, and how you can use them.
You are looking for a list of subjects, with associated text and title, but this may not be unique; more than one null exist for each of the titles. You want to drive the join from table 4, and get a list of subjects, with associated titles for each.
Looking at your ouput it appears you want all subjects displayed. Knowing this you should first off build everything off this table.
SELECT columns
FROM T4
Next build up your inner joins.
SELECT columns
FROM T4 subjectTable
INNER JOIN T3 mapTable
ON mapTable.ID2 = subjectTable.ID2
When happy with them, add on your optional columns with the outer join.
SELECT columns
FROM T4 subjectTable
INNER JOIN T3 mapTable
ON mapTable.ID2 = subjectTable.ID2
LEFT OUTER JOIN T2 textTable
ON textTable.ID = subjectTable.ID4
LEFT OUTER JOIN T1 titleTable
ON titleTable.ID1 = mapTable.ID1
WHERE
subjectTable.ID = 100;

sql simple 3 table join using same table?

I have two tables:
Table 1
id, name1
Table 2
id, name2a, name2b
Table 2's column names name2a, and name2b are references to table 1's id. I need to create a query that pulls both the names out of table 1 based on the id's used in Table 2.
Therefore, if Table one contained:
1 Peter
2 Paul
And Table 2 contained:
1 1 2
2 2 2
Then a select statement should give me:
Peter Paul
Paul Paul
I've gone around the bend trying to build this SQL and the best I came up with was:
SELECT table1.name AS 'name', table1.name AS 'Other name'
FROM table1, table2
WHERE table1.id = table2.name2a
Which only gives me the name2a column correctly.
Any help appreciated! I guess I need to do a join, but I'm really struggling...
Start with your 2nd table and join TWICE to table 1 (different aliases respectively), then get the name field from each aliased Table1 entry.
select
T2.ID,
TJ1.Name1 as FirstName,
TJ2.Name1 as SecondName
from
Table2 t2
join Table1 TJ1
on t2.Name2a = TJ1.ID
join Table1 TJ2
on t2.Name2b = TJ2.ID
select foo.*, t1.x, t2.y
join t1 on t1.id = foo.a
join t1 as t2 on t2.id = foo.b
If there's a chance that col a or col b is null, use a left join.
Have you tried using an INNER JOIN?
SELECT table1.name AS 'name', table1.name AS 'Other name'
FROM table1 INNER JOIN table2 ON table1.id = table2.name2a;
Sorry if I'm no help, not that great at SQL myself hehe.
Your problem is that you need to reference table1 twice: once for the plain table1.name and again to look up what table2 is pointing at. You can join one table in multiple times if you give them aliases:
SELECT t1.name1, o.name1
FROM table1 t1
JOIN table2 t2 ON t1.id = t2.name2a
JOIN table1 o ON t2.name2b = o.id -- And JOIN back to table1 to get the name1

SQL join format - nested inner joins

I have the following SQL statement in a legacy system I'm refactoring. It is an abbreviated view for the purposes of this question, just returning count(*) for the time being.
SELECT COUNT(*)
FROM Table1
INNER JOIN Table2
INNER JOIN Table3 ON Table2.Key = Table3.Key AND Table2.Key2 = Table3.Key2
ON Table1.DifferentKey = Table3.DifferentKey
It is generating a very large number of records and killing the system, but could someone please explain the syntax? And can this be expressed in any other way?
Table1 contains 419 rows
Table2 contains 3374 rows
Table3 contains 28182 rows
EDIT:
Suggested reformat
SELECT COUNT(*)
FROM Table1
INNER JOIN Table3
ON Table1.DifferentKey = Table3.DifferentKey
INNER JOIN Table2
ON Table2.Key = Table3.Key AND Table2.Key2 = Table3.Key2
For readability, I restructured the query... starting with the apparent top-most level being Table1, which then ties to Table3, and then table3 ties to table2. Much easier to follow if you follow the chain of relationships.
Now, to answer your question. You are getting a large count as the result of a Cartesian product. For each record in Table1 that matches in Table3 you will have X * Y. Then, for each match between table3 and Table2 will have the same impact... Y * Z... So your result for just one possible ID in table 1 can have X * Y * Z records.
This is based on not knowing how the normalization or content is for your tables... if the key is a PRIMARY key or not..
Ex:
Table 1
DiffKey Other Val
1 X
1 Y
1 Z
Table 3
DiffKey Key Key2 Tbl3 Other
1 2 6 V
1 2 6 X
1 2 6 Y
1 2 6 Z
Table 2
Key Key2 Other Val
2 6 a
2 6 b
2 6 c
2 6 d
2 6 e
So, Table 1 joining to Table 3 will result (in this scenario) with 12 records (each in 1 joined with each in 3). Then, all that again times each matched record in table 2 (5 records)... total of 60 ( 3 tbl1 * 4 tbl3 * 5 tbl2 )count would be returned.
So, now, take that and expand based on your 1000's of records and you see how a messed-up structure could choke a cow (so-to-speak) and kill performance.
SELECT
COUNT(*)
FROM
Table1
INNER JOIN Table3
ON Table1.DifferentKey = Table3.DifferentKey
INNER JOIN Table2
ON Table3.Key =Table2.Key
AND Table3.Key2 = Table2.Key2
Since you've already received help on the query, I'll take a poke at your syntax question:
The first query employs some lesser-known ANSI SQL syntax which allows you to nest joins between the join and on clauses. This allows you to scope/tier your joins and probably opens up a host of other evil, arcane things.
Now, while a nested join cannot refer any higher in the join hierarchy than its immediate parent, joins above it or outside of its branch can refer to it... which is precisely what this ugly little guy is doing:
select
count(*)
from Table1 as t1
join Table2 as t2
join Table3 as t3
on t2.Key = t3.Key -- join #1
and t2.Key2 = t3.Key2
on t1.DifferentKey = t3.DifferentKey -- join #2
This looks a little confusing because join #2 is joining t1 to t2 without specifically referencing t2... however, it references t2 indirectly via t3 -as t3 is joined to t2 in join #1. While that may work, you may find the following a bit more (visually) linear and appealing:
select
count(*)
from Table1 as t1
join Table3 as t3
join Table2 as t2
on t2.Key = t3.Key -- join #1
and t2.Key2 = t3.Key2
on t1.DifferentKey = t3.DifferentKey -- join #2
Personally, I've found that nesting in this fashion keeps my statements tidy by outlining each tier of the relationship hierarchy. As a side note, you don't need to specify inner. join is implicitly inner unless explicitly marked otherwise.

MySQL: Multi-column join on several tables

I have several tables that I am joining that I need to add another table to and I can't seem to get the right query. Here is what I have now -
Table 1
carid, catid, makeid, modelid, caryear
Table 2
makeid, makename
Table 3
modelid, modelname
Table 4
catid, catname
The query I am using to join these is:
SELECT * FROM table1 a
JOIN table2 b on a.makeid=b.makeid
JOIN table3 c on a.modelid=c.modelid
JOIN table4 d on a.catid=d.catid
WHERE a.carid = $carid;
Now I need to add a 5th table that I am getting from a 3rd party that I am having a hard time adding to my existing query. The new table has these fields -
Table 5
id, year, make, model, citympg, hwympg
I need the citympg and hwympg based on caryear from table 1, makename from table 2, and modelname from table 3. I know I can do a second query with those values, but I would prefer to do a single query and have all of the data in a single row. Can this be done in a single query? If so, how?
it's possible to have more than condition in a join.
does this work?
SELECT a.*, e.citympg, e.hwympg
FROM table1 a
JOIN table2 b on a.makeid=b.makeid
JOIN table3 c on a.modelid=c.modelid
JOIN table4 d on a.catid=d.catid
Join table5 e on b.makename = e.make
and c.modelname = e.model
and a.caryear = e.year
WHERE a.carid = $carid;
...though your question is not clear. Did you only want to join table5 to the others, or was there something else you wanted to do with table5?
Without indexes, It won't be efficient, but you can do
LEFT JOIN table5 ON (table2.make = table5.make AND table3.model = table5.model AND table1.caryear = table5.caryear)
This also assumes the make and models and years strings match exactly.