MS Access 2007 Inner Join on Same Table - sql

I have a table t1. It has columns [id] and [id2].
Select count(*) from t1 where id=1;
returns 31,189 records
Select count(*) from t1 where id=2;
returns 31,173 records
I want to know the records where id2 is in id=1 but not in id=2.
So, I use the following:
Select * from t1 a left join t1 b on a.id2=b.id2
Where a.id=2 And b.id=1
And b.id2 Is Null;
It returns zero records.
Using an inner join to see how many records have id2 in common, I do...
Select * from t1 a inner join t1 b on a.id2=b.id2
Where a.id=2 And b.id=1;
And that returns 31,060. So where are the extra records in my first query that don't match?
I am sure I must be missing something obvious.
Sample Data
id id2
1 101
1 102
1 103
2 101
2 102
My expected results is to find the record with '103' in it. 'id2' not shared.
Thanks for any help.
Jeff

You are attempting to do what is generally called an exclude join. This involves doing a LEFT JOIN between two tables, then using a WHERE clause to only select rows where the right table is null, i.e. there was no record to join. In this way, you select everything from the left table except what exists in the right table.
With this data, it would look something like this:
SELECT
t1.id,
t1.id2
FROM test_table t1
LEFT JOIN
(SELECT
id,
id2
FROM test_table
WHERE id = 2) t2
ON t2.id2 = t1.id2
WHERE t1.id = 1
AND t2.id IS NULL --This is what makes the exclude join happen
And here is a SQLFiddle demonstrating this in MySQL 5.7 with the sample data you provided.

I think maybe Access changes the left join to an inner join when you add a where clause to filter rows (I know SQL Server does this), but if you do the filtering in derived tables it should work:
select
a.*
from
(select * from t1 where id = 1) a
left join
(select * from t1 where id = 2) b
on a.id2 = b.id2
where b.id2 is null

Related

SQL statement to check if data exists in one table and not in two other tables

I'm creating 1 temp table (temp1) using table1.
and I want to check if data from temp table is present in table1 and table2.
table1 and table2 have same columns.
It's difficult to assess exactly what you need without further detail, but you could try a LEFT JOIN and a COUNT here to indicate whether there are any matching rows (whereby anything over 0 indicates matching rows)
SELECT
COUNT(*) AS matching_rows
FROM
(
SELECT
1 AS 'ColumnA'
) AS T1
LEFT OUTER JOIN
(
SELECT
2 AS 'ColumnA'
) AS T2
ON T1.ColumnA = T2.ColumnA
WHERE
T2.ColumnA IS NOT NULL
You can also use an INNER JOIN for this:
SELECT
COUNT(*) AS matching_rows
FROM
(
SELECT
1 AS 'ColumnA'
) AS T1
INNER JOIN
(
SELECT
2 AS 'ColumnA'
) AS T2
ON T1.ColumnA = T2.ColumnA

How to fetch * records from a table which are not present in other two tables

I want to fetch all records with all columns of a table, Records which are not in the other 2 tables. Please help.
I have tried below query, it is working fine for comparing one column. But I want to compare 5 columns.
select * from A
WHERE NOT EXISTS
(select * from B b where b.id=a.id) AND
NOT EXISTS
(select * from C c where c.id=a.id)
A general solution might look like:
SELECT t1.*
FROM table1 t1
WHERE NOT EXISTS (SELECT 1 FROM table2 t2 WHERE t2.id = t1.t2_id) AND
NOT EXISTS (SELECT 1 FROM table3 t3 WHERE t3.id = t1.t3_id);
This assumes that you want to target table1 for records, ensuring that no matches can found in table2 and table3.
I prefer this approach:
SELECT t1.*
FROM table1 AS t1
LEFT JOIN table2 AS t2
ON t1.id = t2.t1_id
LEFT JOIN table3 AS t3
ON t1.id = t3.t1_id
WHERE t2.id IS NULL
AND t3.id IS NULL;
While this might be a bit less intuitive than using sub queries I think odds of making mistakes with aliases are less likely as in the example below, which happens more often than you might expect:
SELECT *
FROM table1
WHERE NOT EXISTS (SELECT 1 FROM table2 WHERE id = id) AND
NOT EXISTS (SELECT 1 FROM table3 WHERE id = id);
To your question about checks on 5 columns, that can still be done using either of these methods by adding conditions either in the left joins or in the where clause of each sub query.

SQL Query of 2 tables finding missing value in table 2

I have 2 tables in SQL.
-Table 1-
Name
ID
-Table 2-
ID
Program
Table 1 only holds a single record for each company. In table 2, there can be multiple entries for a record in table 1. So I could join the two tables together on ID = ID and get anywhere from 0 to 7 results. I need to query the 2 tables where I am looking for any company from table 1 who is not in a specific program but they can be in other programs. I know this is easy to do but I just can't get it to work for me.
SELECT *
FROM
Table1 t1
LEFT JOIN Table2 t2
ON t1.id = t2.id
AND t2.program = 'asdf'
WHERE
t2.id IS NULL
Just use an OUTER JOIN place the program requirement on the join condition and then say where a record for the Table2 doesn't exist.
Trying to make this a little less ambiguous and adapting to your specific companies and programs:
SELECT *
FROm
Companies c
LEFT JOIN Programs p
ON c.Id = p.CompanyId
AND p.Program = 'some title'
WHERE
p.Program IS NULL
And the NOT exists method:
SELECT *
FROM
Companies c
WHERE
NOT EXISTS (SELECT 1
FROM Programs p
WHERE
p.CompanyId = c.Id
AND p.Program = 'some title')
I don't show the NOT IN method because I don't recommend it typically.
You want to get companies where they aren't in a program that you specify in the query? This is what I came up with:
select t1.*
from Table1 t1
left join Table2 t2 on t1.ID = t2.ID
where coalesce(t2.Program, '') <> 'Name of Program'
or
where coalesce(t2.Program, '') not in (<comma-delimited list of programs>)
SELECT t1.Name
FROM Table1 t1
LEFT JOIN
Table2 t2
ON t1.id = t2.id
WHERE t2.program IS NULL;

Select if else sql

I have two table say T1 and T2 and one column C is common to both. I need an SQL query in which if C is null in T1 it will select from other table.
I tried writing SELECT statement in THEN clause but not running. Don't know is there any IF ELSE clause in SQL.
Select C, case when c = null Then Select c from T2
from T1
Even better, most RDBMSs support COALESCE, which lets you check multiple values and return the first non-null value.
SELECT COALESCE(T1.C, T2.C) AS C
FROM T1
LEFT OUTER JOIN T2 ON T1.[Primary Key] = T2.[Primary Key]
Is this in TransactSQL?
I like the first answer, however you could also do it this way...
select case t1.C
when null then t2.C
else t1.C
end as [testC]
from t1
inner join t2
on t1.PKID = t2.PKID
What you seem to need is a union
select c from t1
where c is not null
union
select c from t2
where c is not null
Now you get all the columns C from T1and T2 in one result set but only if not null.
Well of course if this has simplified your problem too much you need to work with a join
select coalesce(t1.c,t2.c) as c
from t1
left join t2 on (t2.id = t1.foreign_id)
This assumed that T2.ID is the primary key and related to T1 with T1.FOREIGN_ID
It is important that you do a left join because otherwise you only get T1 rows when the row also exists in T2.

sql, outer join

I have two tables, linked with an outer join. The relationship between the primary and secondary table is a 1 to [0..n]. The secondary table includes a timestamp column indicating when the record was added. I only want to retrieve the most recent record of the secondary table for each row in the primary. I have to use a group by on the primary table due to other tables also part of the SELECT. There's no way to use a 'having' clause though since this secondary table is not part of the group.
How can I do this without doing multiple queries?
For performance, try to touch the table least times
Option 1, OUTER APPLY
SELECT *
FROM
table1 a
OUTER APPY
(SELECT TOP 1 TimeStamp FROM table2 b
WHERE a.somekey = b.somekey ORDER BY TimeStamp DESC) x
Option 2, Aggregate
SELECT *
FROM
table1 a
LEFT JOIN
(SELECT MAX(TimeStamp) AS maxTs, somekey FROM table2
GROUP BY somekey) x ON a.somekey = x.somekey
Note: each table is mentioned once, no correlated subqueries
Something like:
SELECT a.id, b.*
FROM table1 a
INNER JOIN table2 b ON b.parentid = a.id
WHERE b.timestamp = (SELECT MAX(timestamp) FROM table2 c WHERE c.parentid = a.id)
Use LEFT JOIN instead of INNER JOIN if you want to show rows for IDs in table1 without any matches in table2.
select *
from table1 left outer join table2 a on
table1.id = a.table1_id
where
not exists (select 1 from table2 b where a.table1_id = b.table1_id and b.timestamp > a.timestamp)
The quickest way I know of is this:
SELECT
A.*,
B.SomeField
FROM
Table1 A
INNER JOIN (
SELECT
B1.A_ID,
B1.SomeField
FROM
Table2 B1
LEFT JOIN Table2 B2 ON (B1.A_ID=B2.A_ID) AND (B1.TimeStmp < B2.TimeStmp)
WHERE
B2.A_ID IS NULL
) B ON B.A_ID = A.ID