Oracle join tables with multiple conditions - sql

I ve post a pic of what im trying to accomplish ive been trying all the codes i can find online but nothing seems to work.
here a snippet of the code i'm trying to use.. Am i even on the right track? PS. its an oracle DB
SELECT
q1.x, q1.y, q2.z, ...
FROM
(SELECT ... FROM ...) q1
LEFT JOIN
(SELECT ... FROM ...) q2
ON q1.column = q2.column
thank you for help!

Unless I'm missing something profound, this is just two joins:
select t1.*, t2a.text as text1, t2a.text as text2
from t1 join
t2 t2a
on t2a.num = t1.num1 join
t2 t2b
on t2b.num = t1.num2;

You need to join Table 2 twice, once on Table1.NUM1 and once on Table1.NUM2:
SELECT
t1.A, t1.NUM1, t1.NUM2, t2a.TEXT AS TEXT1, t2b.TEXT AS TEXT2
FROM
Table1 t1
INNER JOIN Table2 t2a
ON t1.NUM1 = t2a.NUM
INNER JOIN Table2 t2b
ON t1.NUM2 = t2b.NUM
You can also use LEFT JOINS, if rows from Table 2 are missing and you still want to include the rows of Table 1 in such cases.
In order to be able to identify the 2 instances of Table 2 you need to give them different aliases. The alias on Table 1 is just for convenience.

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.

Complex SQL Join on sub query with top 1 records

I'm trying to write a query that looks something like below.
select t1.t1c1, t1.t1c2, t2.t2c3, t2.t2c4
from table1 t1
left outer join (select top 1 t2c1, t2c2, t2c3, t2c4 from table2
where t2c5 in (select t3c1 from table3 t3
where **t3c2 = t1.t1c2 and t3c3 = t1.t1c3**) t2
on t1.t1c1 = t2.t2c1 and t1.t1c2 = t2.t2c2
What SQL Server does not allow is the highlighted text above - i.e. referencing the table1's columns in the table3 sub query.
Is there a way to achieve this?
I understand that this might not be the most optimal way, is there any other way to achieve this?
You seem to exactly want outer apply. I think it would look like this:
select t1.t1c1, t1.t1c2, t2.t2c3, t2.t2c4
from table1 t1 outer apply
(select top 1 t2c1, t2c2, t2c3, t2c4
from table2
where t2c5 in (select t3c1
from table3 t3
where t3c2 = t1.t1c2 and t3c3 = t1.t1c3
) and
t1.t1c1 = t2.t2c1 and t1.t1c2 = t2.t2c2
) t2;
APPLY is a lot like using a correlated subquery, except it goes in the FROM clause and can return multiple columns and multiple rows.
Note: You should be using ORDER BY when you use TOP.

How to select records that do not exist in two (or more) tables

I have 3 tables of accounts that all contain the same fields. Table1 contains all accounts while Table2 and Table3 contain subsets of the accounts. I'm trying to select records in Table1 that do no exist in Table2 or Table3.
Let's say the table layout is like this and is the same for all 3 tables:
|AcctNum|Name|State|
I know how to do this if it was just Table1 and Table2, using a left join and Is Null, but the 3rd table is throwing me. Is this possible to do in one query? Can you combine left joins? I should point out I'm using Access 2010.
Yes you can combine left joins and with the odd syntax Access uses the query should look like this:
SELECT T1.AcctNum
FROM (Table1 AS T1 LEFT JOIN Table2 AS T2 ON T1.AcctNum = T2.AcctNum)
LEFT JOIN Table3 AS T3 ON T1.AcctNum = T3.AcctNum
WHERE (((T2.AcctNum) Is Null) AND ((T3.AcctNum) Is Null));
You can use Access to create a view called TableCombined that is a union of both Table2 and Table3.
At that point, you can use your left join and Is Null query and join TableCombined to Table1.
Hope this helps!
You can also do a NOT EXISTS statement which makes sense logically for what you are trying to achieve.
For example:
SELECT ACCTNUM
FROM TABLE1
WHERE NOT EXISTS (SELECT TABLE2.ACCTNUM FROM TABLE2 INNER JOIN TABLE3 WHERE TABLE2.ACCTNUM IS NULL AND TABLE3.ACCTNUM IS NULL)

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;

A question about JOIN

I need to do something like this to fill a parts table:
SELECT (CASE t1.part IS NULL THEN t2.part ELSE t1.part END) AS partno,
t3.desc
FROM t1
LEFT JOIN join t2 ON [certain condition]
LEFT JOIN t3 ON t1.part = t3.part
OR t2.part = t3.part
...so this will select the value for partno from t2 in case that part is null in t1, then i need to take the description from t3 but when I run it it takes forever and never return the results, How can I do this faster? if I am missing some details please ask.
this are the tables
alt text http://img15.imageshack.us/img15/3878/74385879.png
this is the actual procedure
DELIMITER $$
DROP PROCEDURE IF EXISTS `getMonthDetail` $$
CREATE DEFINER=`root`#`%` PROCEDURE `getMonthDetail`(fechai Date, wid int)
BEGIN
select distinct
ins.inventoryinid,
(
select group_concat(concat(documents.documentname,': ', inventoryin_documents.documentno))
from inventoryin_documents
left join documents on documents.documentid=inventoryin_documents.documentid
where inventoryin_documents.inventoryinid = docin.inventoryinid
group by inventoryin_documents.inventoryinid
)as docin,
trace.inventoryoutid,
(
select group_concat(concat(documents.documentname,': ', inventoryout_documents.documentno))
from inventoryout_documents
left join documents on documents.documentid=inventoryout_documents.documentid
where inventoryout_documents.inventoryoutid = docout.inventoryoutid
group by inventoryout_documents.inventoryoutid
) as docout,
outs.inventoryoutdate,
(case when trace.partnumberp is null then indetails.partnumberp else trace.partnumberp end) as nopart,
p.descriptionsmall,
trace.quantity
from
inventoryin as ins
left join inventoryinouttrace as trace on trace.inventoryinid = ins.inventoryinid
left join inventoryin_documents as docin on docin.inventoryinid = ins.inventoryinid
left join inventoryout_documents as docout on docout.inventoryoutid = trace.inventoryoutid
left join inventoryout as outs on outs.inventoryoutid = trace.inventoryoutid
left join inventoryindetails indetails on ins.inventoryinid = indetails.inventoryinid
left join product as p on trace.partnumberp=p.partnumberp
where
((ins.inventorydate > fechai+0 and ins.inventorydate < fechai+100)
or (outs.inventoryoutdate > fechai+0 and outs.inventoryoutdate < fechai+100));
END $$
DELIMITER ;
and when I Hit the explain button in the query browser it returns a error...
Try:
SELECT COALESCE(t1.part, t2.part) AS partno,
COALESCE(t3.desc, t4.desc)
FROM t1
LEFT JOIN join t2 ON [certain condition]
LEFT JOIN t3 ON t3.part = t1.part
LEFT JOIN t3 AS t4 ON t4.part = t1.part
OR's are notorious for poor performance.
OR clauses run slow and you should consider replacing them with a UNION which would still utilize any INDEXES you may have on your t1, t2, and t3 tables:
SELECT IFNULL(t1.part, t2.part) AS partno, t3.desc
FROM t1
LEFT JOIN t2 ON (condition here)
LEFT JOIN t3 ON (t1.part = t3.part)
UNION DISTINCT
SELECT IFNULL(t1.part, t2.part) AS partno, t3.desc
FROM t1
LEFT JOIN t2 ON (condition here)
LEFT JOIN t3 ON (t2.part = t3.part)
Also, your CASE() function, much the same as my simplified IFNULL() function, ends up using a temporary table. This is unavoidable when utilizing such functions.
Tell us the actual structure of the data and please show us the EXPLAIN of the query so we can see why it runs slow!
Only a guess: Are there indexes on the right coumns?
Your certain condition should be t2.id=t1.id and have more where clauses in your WHERE statement.
You may want to simplify this down to just have two select statements and see if it is slow, first.
You may be missing an index that would be helpful.
Once the two selects are fine, then you can add in the case command to the sql, and see what is going on, but don't change anything else in your query.
Then, you can give queries and times, which will help people to give a better answer.
Ok for the bleeding obvious : I suppose you have indexed the fields that you use in your joins?