SQL Join Not Exists - sql

I have the following between these two tables, id column and case column
Left Table Right Table
| id1 | case#1 | | case#1 | id1 |
| id2 | case#1 | | case#1 | id3 |
| id3 | case#2 | | case#2 | id1 |
As you can see case#1 is not assigned to id2 on the right table, therefore I would like to pull the (id2, case#1) record from the left table.

You would need to perform an OUTER JOIN with a multiple JOIN condition:
left_table as l right outer join right_table as r
on l.id = r.id and l.case_ = r.case_
where l.id IS NULL;
This will return non-matching rows from the left table

Have you tried a left join?
LEFT OUTER JOIN table ON table1.field1 = table2.field2
Depends on what you want. If you do INNER JOIN, you get the rows that match in Table1 AND Table2. If you do OUTER JOIN, you get all of Table1 and only the matching rows from Table2.

I've used LEFT JOIN and selected the record with NULL id in the Right Table using WHERE clause. See my query and demo below:
SELECT
*
FROM LeftTable A
LEFT JOIN RightTable B ON A.id=B.id
WHERE B.id IS NULL
DEMO HERE

I would use NOT EXISTS operation in that case.
SELECT l.id, l.value
FROM LeftTable l
WHERE NOT EXISTS (SELECT 1 FROM RightTable r WHERE r.id = l.id and r.case_value = l.case_value)
Efficiency comparing and the difference between NOT EXISTS vs. NOT IN vs. LEFT JOIN WHERE IS NULL are here

Related

SQL case/if condition Join tbl A or tbl B

SQL Server...
I need to Join tbl_B or tbl_C with tbl_A. Case tblA.id = 1 Join B or Case tblA.id = 2 Join C
let's say this example:
Table: tblFood
Id_Food | Fk_Id_Foodtype
1 | 1
1 | 2
Table: tabVegetable
Id | Mame |Color
1 | eggplant |black
Table: tabFrute
Id | Name |Color
1 | apple |red
On the table tblFood above...
if Fk_Id_Foodtype = 1 join Id_Food on tabVegetable
if Fk_Id_Foodtype = 2 join Id_Food on tabFrute
So I can return execute a select like this: SELECT tblFood.Id_Food, (tabVegetable or tabFrute).name, (tabVegetable or tabFrute).color
Note: I only have tblFruts and tblVegetable, so I always check these two option.
Thank you!
Join to tblFood the other tables with LEFT joins and in the ON clauses specify the condition for Fk_Id_Foodtype.
In the SELECT list of columns use COALESCE() to get the values of the columns from each table:
SELECT f.*,
COALESCE(v.Name, fr.Name) Name,
COALESCE(v.Color, fr.Color) Color
FROM tblFood f
LEFT JOIN tabVegetable v ON f.Fk_Id_Foodtype = 1 AND v.Id = f.Id
LEFT JOIN tabFrute fr ON f.Fk_Id_Foodtype = 2 AND fr.Id = f.Id

Joining tables based on the maximum id

I have found three questions which all seem to ask a similar question:
Getting max value from rows and joining to another table
Select only rows by join tables max value
Joining tables based on the maximum value
But I'm having a hard time wrapping my head around how exactly to join tables keeping only the maximum row of one of the tables when the maximum is in the id or index field itself.
I am looking for an answers that only require joins because this will allow the solution to work in a tool which generates queries for which it is easy to get it to generate the corresponding joins, although sub-queries are probably doable as well with a bit more effort. I found the answer below to be of particular interest:
SELECT DISTINCT b.id, b.filename, a1.name
FROM a a1
JOIN b
ON b.id = a1.id
LEFT JOIN a a2
ON a2.id = a1.id
AND a2.rank > a1.rank
WHERE a2.id IS NULL
However, in my case the ranking column is also the index, e.g. "id". I cannot compare for equality and greater than at the same time, because they will never be true at the same time!
Also, potentially complicating the situation is that a typical query in which I have need of this may join several tables (3-5 is not uncommon). So as a simplified example of my query:
SELECT
table1.field1, table1.field2, table1.field3,
table2.field1, table2.field2, table2.field3,
table3.field1, table3.field2, table3.field3,
table4.field1, table4.field2, table4.field3
FROM table1
INNER JOIN table2 ON
table1.field1 = table2.field1
AND table1.field2 = table2.field2
AND table2.field3 < 0
INNER JOIN table3 ON
table2.field1 = table3.field1
AND table2.field4 = table3.field4
INNER JOIN table4 ON
table1.field1 = table4.field1
AND table1.field2 = table4.field2
And what I want to do is to eliminate duplicates in table3 by only getting the row with the maximum id (e.g. MAX(table3.id)) for each unique combination of all the other fields. That is to say, the above query is returning something like this:
+-------+-------+-------+---------+
| table1| table2| table4|table3 |
+-------+-------+-------+---------+
| A | A | A | 1,... |
| A | A | A | 2,... |
| A | A | A | 3,... |
| A | A | A | MAX2,...|
| B | B | B | 1,... |
| B | B | B | 2,... |
| B | B | B | 3,... |
| B | B | B | MAX2,...|
+-------+-------+-------+---------+
(I'm just using A and B to denote that I'm talking about all the same values for the fields in table1, table2, and table4 for a particular set of rows.)
and I want to reduce it to this:
+-------+-------+-------+---------+
| table1| table2| table4|table3 |
+-------+-------+-------+---------+
| A | A | A | MAX1,...|
| B | B | B | MAX2,...|
+-------+-------+-------+---------+
You can add a derived table to reduce the matching rows in TABLE3 to one per group. Another method would use a window function but you asked for a JOIN only
SELECT
table1.field1, table1.field2, table1.field3,
table2.field1, table2.field2, table2.field3,
table3.field1, table3.field2, table3.field3,
table4.field1, table4.field2, table4.field3
FROM table1
INNER JOIN table2 ON
table1.field1 = table2.field1
AND table1.field2 = table2.field2
AND table2.field3 < 0
INNER JOIN table3 ON
table2.field1 = table3.field1
AND table2.field4 = table3.field4
--here is the added derived table. Change column names as needed
INNER JOIN (select UID, ID = max(ID) from Table3 group by UID) x
on x.UID = table3.UID and x.mx = table3.ID
INNER JOIN table4 ON
table1.field1 = table4.field1
AND table1.field2 = table4.field2
Or, perhaps... something like below. It really depends on your schema and that's hard to understand with the sample data.
INNER JOIN (select field1, field4, mx = max(ID) from Table3 group by field1, field4) x
on x.field1 = table3.field1 and x.field4 = table3.field4 and x.mx = table3.ID
Here is an example. You'll notice that the last three column pairs are identical. You only want the last one, which is the max(id) for that grouping. What ever makes a row unique in relation to the rest of your data (not your primary key, but what you are joining with) is what you'd want to include int he derived table and join condition.
declare #table table (id int identity(1,1), f1 char(1), f2 char(1))
insert into #table
values
('a','b'),
('a','c'),
('a','a'),
('b','b'),
('b','b'),
('b','b')
select * from #table
select t1.*
from #table t1
inner join
(select f1, f2, mx = max(id) from #table group by f1, f2) t2 on
t1.f1 = t2.f1
and t1.f2 = t2.f2
and t1.id = t2.mx

combinations (not permutations) from cross join in sql

If I have a table that I'd like to cross join to itself, how can I remove the duplicate rows? Or to put it another way, how can I do a "order doesn't matter" cross join?
So for example, if I have a table T:
field |
-------
A |
B |
C |
and I cross join to itself so that i don't get the A | A rows
T as t1
cross join
T as t2
on t1.field != t2.field
I would get the following:
field | field
------+-------
A | B
A | C
B | A
B | C
C | A
C | B
However, to me A, B is the same as B, A.
Is there a good way to remove these duplicates? In other words, I want the combinations not the permutations.
T as t1
inner join
T as t2
on t1.field < t2.field
FWIW, you can just use INNER JOIN for this, it's not strictly a CROSS JOIN. MySQL (and perhaps some other RDBMS) treats these two types of join as identical, but in ANSI SQL, a cross join has no join condition -- it's a deliberate Cartesian product.

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