IF condition in INNER JOIN SQL Query - sql

I have a problem in writing sql query. Here is the illustration about my problem.
I have 2 tables in the database as follows :
| Table A | | Table B |
| idTableA | | idTableB |
| idPriority | | idReference |
Those tables above are related. The idReference in Table B is referring to idPriority in Table A. BUT if the value of the idPriority is NULL, then the idReference should be referring to idTableA. Hope you guys get the illustration and can help me working with this problem. Thx in advance.

Double-join method, easy to read
select
B.idTableB,
isnull(A1.idPriority, A2.idTableA) as RefValue
from
TableB as B
left join TableA as A1 on A1.idPriority = B.idReference
left join TableA as A2 on A1.idTableA = B.idReference
Single-join method, two IsNulls()'s:
select
B.idTableB,
isnull(A1.idPriority, A1.idTableA) as RefValue
from
TableB as B
left join TableA as A1 on isnull(A1.idPriority, A1.idTableA) = B.idReference

would the following construct work for you?
select *
from tableA join tableB on (join condition)
where (idpriority is not null)
union
select *
from tableA join tableB on (join condition)
where (idpriority is null)

select *
from tableB b
join tableA a
on
a.idPriority = b.idReference
or
(a.idPriority IS NULL AND b.idReference = a.idTableA)

Related

Proper Left join of three tables - SQL

Update - Ok the three answers all make sense, i'm going to try them each as I am curious if there is a performance +/- but i'm not sure I have enough test data in my tables to determine that.
I am trying to look at Table A and search to see if a user exists in Table B or Table C so as to find anyone form table A who does not exists in at least one of the other two tables (they do not need to exists in both, just B or C)
Something like this but without having to have to almost identical statements below
SELECT emp_id
FROM
tableA
LEFT JOIN
TableB
ON
tableA.emp_id = tableB.emp_id
WHERE
TableA.emp_id IS NULL
SELECT emp_id
FROM
tableA
LEFT JOIN
TableC
ON
tableA.emp_id = tableC.emp_id
WHERE
TableA.emp_id IS NULL
Table A
+---------+--------+-----------+
| Emp_ID | Status | hire_date |
+---------+--------+-----------+
| 12345 | happy | 10/10/2005|
| 54321 | sad | 12/01/2009|
+---------+--------+-----------+
Table B
+---------+--------+
| Emp_ID | Weight |
+---------+--------+
| 12345 | 185 |
| 54321 | 150 |
+---------+--------+
Table C
+---------+--------+
| Emp_ID | City |
+---------+--------+
| 12345 | Chicago|
| 54321 | Atlanta|
+---------+--------+
Thanks for any suggestions!
You can join all tables in a single query.
SELECT a.Emp_ID -- a.* <<== if you want to include all columns
FROM tbA a
LEFT JOIN tbB b
ON a.Emp_ID = b.Emp_ID
LEFT JOIN tbC c
ON a.Emp_ID = c.Emp_ID
WHERE b.Emp_ID IS NULL
AND c.Emp_ID IS NULL -- <<== AND should be use here
Why not just express the query using not in?
SELECT emp_id
FROM tableA
WHERE emp_id not in (select emp_id from TableB) and
emp_id not in (select emp_id from TableC);
you can join 3 table simply as below
Select emp_id from table1 a left join table2 b on a.emp_id=b.emp_id
left join table3 c on c.emp_id=a.emp_id
Your query can't work because you have a WHERE tableA.emp_id IS NULL, and TableA is the emp_id you want to test for, you should have tested with TableB.eemp_id IS NULL and TableC.emp_id IS NULL for the second query.
Since you want rows that do not exists in at least tableB or tableC, you can do a LEFT JOIN with both tableB and tableC and test if at least one of the emp_id in those tables IS NULL with a OR
SELECT emp_id
FROM tableA
LEFT JOIN TableB ON tableA.emp_id = tableB.emp_id
LEFT JOIN TableC ON tableA.emp_id = tableC.emp_id
WHERE
TableB.emp_id IS NULL
OR TableC.emp_id IS NULL

Postgresql tables intersect

I have a two tables in my postgresql database.
Both tables have same columns.
How can i prefer values from tableA which are not null?
TableA
id | name
1 | val_a_1
2 | val_a_2
3 | (null)
TableB
id | name
1 | (null)
2 | val_b_2
3 | val_b_3
Result which i want to get:
id | name
1 | val_a_1
2 | val_a_2
3 | val_b_3
For now I've got it like this, but its more complicated, because there are lots of columns.
SELECT *
CASE
WHEN TableA.name is NULL or TableA.name = ''
THEN (SELECT TableB.name FROM TableB where TableB.id = 1)
ELSE TableA.name
END
AS name,
CASE
.
. another columns
.
END
Thanks
why not use COALESCE? Assuming all recordID in tableA is present on Table2
SELECT a.ID,
COALESCE(a.name, b.name) AS "Name"
FROM TableA a
INNER JOIN TableB b
ON a.ID = b.ID
SQLFIddle Demo
Conditional Expressions
The COALESCE function returns the first of its arguments (there can be more arguments) that is not null.
It's all about the COALESCE, not the join itself.
you can use a full outer join for the values which exist in tableA but not in tableB and vice versa:
select coalesce(tableA.ID, tableB.ID) as ID,
coalesce(tableA.Name, tableB.Name) as Name
from tableA full outer join tableB on tableA.ID = tableB.ID

Select first record in a One-to-Many relation using left join

I'm trying to join two tables using a left-join. And the result set has to include only the first record from the "right" joined table.
Lets say I have two tables A and B as below;
Table "A"
code | emp_no
101 | 12222
102 | 23333
103 | 34444
104 | 45555
105 | 56666
Table "B"
code | city | county
101 | Glen Oaks | Queens
101 | Astoria | Queens
101 | Flushing | Queens
102 | Ridgewood | Brooklyn
103 | Bayside | New York
Expected Output:
code | emp_no | city | county
101 | 12222 | Glen Oaks | Queens
102 | 23333 | Ridgewood | Brooklyn
103 | 34444 | Bayside | New York
104 | 45555 | NULL | NULL
105 | 56666 | NULL | NULL
If you notice my result has only the one matched record from table "B"(doesn't matter what record is matched) after left join (and it is a one to many mapping)
I need to pick the first matched record from table B and ignore all other rows.
Please help!
Thanks
After playing around a bit, this turns out to be trickier than I'd expected! Assuming that table_b has some single column that is unique (say, a single-field primary key), it looks like you can do this:
SELECT table_a.code,
table_a.emp_no,
table_b.city,
table_b.county
FROM table_a
LEFT
JOIN table_b
ON table_b.code = table_a.code
AND table_b.field_that_is_unique =
( SELECT TOP 1
field_that_is_unique
FROM table_b
WHERE table_b.code = table_a.code
)
;
Another option: OUTER APPLY
If supported by the database, OUTER APPLY is an efficient and terse option.
SELECT *
FROM
Table_A a
OUTER APPLY
(SELECT TOP 1 *
FROM Table_B b_1
WHERE b_1.code = a.code
) b
;
This results in a left join to the indeterminate first matched record. My tests show it to be quicker than any other posted solution (on MS SQL Server 2012).
The highest voted answer does not seem correct to me, and seems overcomplicated.
Just group by the code field on table B in your subquery and select the maximum Id per grouping.
SELECT
table_a.code,
table_a.emp_no,
table_b.city,
table_b.county
FROM
table_a
LEFT JOIN
table_b
ON table_b.code = table_a.code
AND table_b.field_that_is_unique IN
(SELECT MAX(field_that_is_unique)
FROM table_b
GROUP BY table_b.code)
If you are on SQL Server 2005 or later version, you could use ranking to achieve what you want. In particular, ROW_NUMBER() seems to suit your needs nicely:
WITH B_ranked AS (
SELECT
*,
rnk = ROW_NUMBER() OVER (PARTITION BY code ORDER BY city)
FROM B
)
SELECT
A.code,
A.emp_no,
B.city,
B.county
FROM A
LEFT JOIN B_ranked AS B ON A.code = B.code AND b.rnk = 1
OR
WITH B_unique_code AS (
select * from(
SELECT
*,
rnk = ROW_NUMBER() OVER (PARTITION BY code ORDER BY city)
FROM B
) AS s
where rnk = 1
)
SELECT
A.code,
A.emp_no,
B.city,
B.county
FROM A
LEFT JOIN B_unique_code AS B ON A.code = B.code
I modified the answer from ruakh and this seem to work perfectly with mysql.
SELECT
table_a.code,
table_a.emp_no,
table_b.city,
table_b.county
FROM table_a a
LEFT JOIN table_b b
ON b.code = a.code
AND b.id = ( SELECT id FROM table_b
WHERE table_b.code = table_a.code
LIMIT 1
)
;
this is how:
Select * From TableA a
Left Join TableB b
On b.Code = a.Code
And [Here put criteria predicate that 'defines' what the first record is]
Hey, if the city and county are unique, then use them
Select * From TableA a
Left Join TableB b
On b.Code = a.Code
And b.City + b.county =
(Select Min(city + county)
From TableB
Where Code = b.Code)
But the point is you have to put some expression in there to tell the query processor what it means to be first.
In Oracle you can do:
WITH first_b AS (SELECT code, min(rowid) AS rid FROM b GROUP BY code))
SELECT a.code, a.emp_no, b.city, b.county
FROM a
INNER JOIN first_b
ON first_b.code = a.code
INNER JOIN b
ON b.rowid = first_b.rid

sql select all but nulls

I want to get values from two tables like in the following example:
Suppose we have this two tables:
TableA (with link to tableB):
Id | Id_TableB | Name
---------------------
1 | 1 | Ralf
2 | NULL | Marta
TableB:
Id | Color
---------------------
1 | Blue
2 | Red
I would like to get values for Color if there is a link, NULL otherwise:
Result:
Id | Name | Color
-----------------------------
1 | Ralf| Blue
2 | Marta| NULL
Any ideas on how to solve this?
You need a left outer join .
SELECT t1.Id, t1.Name, t2.Color
from TableA t1 left outer join TableB t2
on t1.Id_TableB = t2.Id;
Please check the link that I have provided above. Its a simplified tutorial
select
a.Id,
a.Name,
b.Color
from
a
left outer join
b
on
a.Id_TableB = b.Id
group by
b.Id
The group by b.Id is necessary if you have a one-to-many relationship a->b.
You need to use a LEFT OUTER JOIN, which includes rows even when there are NULLs. Something like this:
SELECT *
FROM TableA a
LEFT OUTER JOIN TableB b on a.ID_TableB = b.ID
More info here:
http://msdn.microsoft.com/en-us/library/ms187518.aspx
Hope this helps,
John
just you have to use outer join for this....
select a.id,a.Name, b.Color from tableB as b
left join tableA as a on b.Id = a.id_tableB
and for this you can use in condition as well
you can try below query--
select a.id,a.Name, b.Color from tableB as b,tableA as a on b.Id(+) = a.id_tableB

SQL join problem

I want to retrieve all records from one table when there are no matches in the second table.
So it is kind of the opposite of an inner join.
You need a LEFT JOIN WHERE IS NULL query (aka outer join):
SELECT table1.*
FROM table1
LEFT OUTER JOIN table2
ON table1.id = table2.id
WHERE table2.id IS NULL
Or a NOT IN:
SELECT *
FROM table1
WHERE id NOT IN (SELECT id FROM table2)
You have three options:
Correlated sub-query.
SELECT * FROM TableA
WHERE NOT EXISTS
(SELECT * FROM TableB WHERE TableB.ID = TableA.ID)
Non-correlated sub-query.
SELECT * FROM TableA
WHERE ID NOT IN (SELECT ID FROM TableB)
OUTER JOIN with NULL elimination.
SELECT * FROM TableA
LEFT [OUTER] JOIN TableB
ON TableA.ID = TableB.ID
WHERE TableB.ItsPrimaryKey IS NOT NULL
In the last example some DBMSes require the word OUTER, some permit it, and some do not allow it at all.
Depending on the DBMS, the various options might produce different execution plans and different performance. Select the one with good performance and that best expresses your intent.
It's an outer join:
SELECT *
FROM tableA AS a
LEFT JOIN tableB AS b USING(x)
Say you have:
tableA:
a | x
-----
1 | 1
3 | 3
table B:
b | x
-------
1 | 'a'
2 | 'b'
then the query above will give you
a | b | x
------------
1 | 'a' | 1
3 | NULL | 3
if you want
a | b | x
----------------
1 | 'a' | 1
NULL | 'b' | 2
3 | NULL | 3
you have to use FULL OUTER JOIN instead of LEFT JOIN.
EDIT: As Larry Lustig told me (and I think is correct after rereading the question) the OP does not want any rows from B. So the query should be:
SELECT a.*
FROM tableA AS a
LEFT JOIN tableB AS b USING(x)
WHERE b.x IS NULL
that will yield
a | x
-------
3 | 3
The "opposite" of inner join is called outer join.
Outer join. Technically possibly FULL OUTER JOIN ;)
Adding to the Solution of Johannes Weiß the solution to your other question about finding objects in table a without objects in table b:
SELECT *
FROM tableA AS a
LEFT JOIN tableB AS b
USING(x)
WHERE b.foo IS NULL
You are looking for LEFT JOIN or FULL OUTER JOIN
Not all DBMS support FULL though.
Simulation of it is possible with UNION, example in MySQL:
SELECT * FROM t1
LEFT JOIN t2 ON t1.id = t2.id
UNION
SELECT * FROM t1
RIGHT JOIN t2 ON t1.id = t2.id
I believe you are looking for FULL OUTER JOIN (works with Oracle 9i+).
EDIT: didn't read your question well... LEFT JOIN if you only want NULL values for the second table