Microsoft Access query - not returning all data - sql

Suppose I have the following tables:
Table1: FLP, FNAME, LNAME
Table2: FLP, Job, Company, Location
Table3: FLP, Status, Salary, Position
All are linked together by the FLP.
When I am trying to query to get all fields in all tables suppose my query is the following
Select *
From Table1, Table2, Table3
Where Table1.FLP = Table2.FLP AND Table1.FLP = Table3.FLP
However, suppose that one of the tables does not contain information or the record thus doesn't have an FLP.
For example: If i inserted into table1 johndoe1, john, doe,
and into table2 johndoe1, developer, comp, usa,
but did not insert anything into table 3 since the information is optional
my query will not fetch the result since it will fail at Table1.FLP= Table3.FLP
Sometimes table2 does not contain any information
If i tried my query as follows
Select *
From Table1, Table2, Table3
Where Table1.FLP = Table2.FLP OR Table1.FLP = Table3.FLP
then it will fetch all the results but mixes them up for example johndoe1 will have information from table3 that isn't equal to johndoe1 thus creating multiple results with different values.
If needed more explanation or the real table design please let me know.

You should use LEFT JOIN:
Select * From Table1 LEFT JOIN Table2 ON Table1.FLP = Table2.FLP LEFT JOIN Table3 ON Table1.FLP = Table3.FLP;
This will give you a null entry whenever there is no matching element in a right hand table.
See: http://msdn.microsoft.com/en-us/library/bb208894%28v=office.12%29.aspx

Related

Why would LEFT JOIN on a field to then later filter it out in WHERE clause?

Query
SELECT ID, Name, Phone
FROM Table1
LEFT JOIN Table2 ON Table1.ID = Table2.ID
WHERE Table2.ID IS NULL
Problem
Finding it hard to understand why someone would left join on an ID
and then set it to NULL in the where clause?
Am I missing something here? Is there any significance to this?
Could we just omit the Table2 altogether? As in not join at all?
Any help would be much appreciated.
The query you have in the question is basically equivalent to the following query:
SELECT ID, Name, Phone
FROM Table1
WHERE NOT EXISTS
(
SELECT 1
FROM Table2
WHERE Table1.ID = Table2.ID
)
Meaning it selects all the records in Table1 that does not have a correlated record in Table2.
The execution plan for both queries will most likely be the same (Personally, I've never seen a case when they produce a different execution plan, but I don't rule that out), so both queries should be equally efficient, and it's up to you to decide whether the left join or the exists syntax is more readable to you.
I think you should have an alias for you table and specify which table each column is coming from.
Assuming Name is from table one and Phone is form table two and ID is common in both, then the Left join mentioned above may help get all users that do not have phone numbers.
Table 1
Id Name
1 John Smith
2 Jane Doe
Table 2
Id Phone
2 071 555 0863
Left Join without the where clause
ID Name Phone
1 John Smith NULL
2 Jane Doe 071 555 0863
Left Join with the where clause
ID Name Phone
1 John Smith NULL
This is one of the ways to implement the relational database operation of antijoin, called anti semi join within sql server's terminology. This is essentially "bring rows from one table that are not in another table".
The ways I cant think of doing this are:
select cols from t1 left join t2 on t1.key=t2.key where t2.key is null
select cols from t1 where key not in (select key from t2)
select cols from t1 where not exists (select 1 from t2 where t1.key=t2.key)
and even
select * from t1 where key in (select key from t1 except select key from t2)
There are some differences between these methods (most notably, the danger of null handling in the case of not in), but they generally do the same.
To address your points:
Finding it hard to understand why someone would left join on an ID and
then set it to NULL in the where clause?
As mentioned, in order to exclude results from t1 that are present in t2
Could we just omit the Table2 altogether? As in not join at all?
If you don't use the join (or any of its equivelant alternatives), you will get more results, as the rows in table1 that have the same id with any rows in table2 will be returned, too.
If joining condition column is having null value specifically ID then it is bad database design per my understanding.
As per your query below. Here are the possible scnario why where clause make sense
I am assuming that your name and phone number are coming from table2 and then you are trying to find the name and phone number whose ID is null.
If name and phone number is coming from table1 and table 2 is just having ID join and not selecting anything from table 2 then where clause is total waste.
SELECT
ID,
Name,
Phone
FROM
Table1
LEFT JOIN
Table2
ON
Table1.ID = Table2.ID
WHERE
Table2.ID IS NULL
Essentially in the above common business scenario, developers put where clause filter criteria in left join when any value is coming from right side is having non relevance data and not required to be the part of dataset then filter it out.

Cross joining tables to see which partners in one table have a report from another table [duplicate]

table1 (id, name)
table2 (id, name)
Query:
SELECT name
FROM table2
-- that are not in table1 already
SELECT t1.name
FROM table1 t1
LEFT JOIN table2 t2 ON t2.name = t1.name
WHERE t2.name IS NULL
Q: What is happening here?
A: Conceptually, we select all rows from table1 and for each row we attempt to find a row in table2 with the same value for the name column. If there is no such row, we just leave the table2 portion of our result empty for that row. Then we constrain our selection by picking only those rows in the result where the matching row does not exist. Finally, We ignore all fields from our result except for the name column (the one we are sure that exists, from table1).
While it may not be the most performant method possible in all cases, it should work in basically every database engine ever that attempts to implement ANSI 92 SQL
You can either do
SELECT name
FROM table2
WHERE name NOT IN
(SELECT name
FROM table1)
or
SELECT name
FROM table2
WHERE NOT EXISTS
(SELECT *
FROM table1
WHERE table1.name = table2.name)
See this question for 3 techniques to accomplish this
I don't have enough rep points to vote up froadie's answer. But I have to disagree with the comments on Kris's answer. The following answer:
SELECT name
FROM table2
WHERE name NOT IN
(SELECT name
FROM table1)
Is FAR more efficient in practice. I don't know why, but I'm running it against 800k+ records and the difference is tremendous with the advantage given to the 2nd answer posted above. Just my $0.02.
SELECT <column_list>
FROM TABLEA a
LEFTJOIN TABLEB b
ON a.Key = b.Key
WHERE b.Key IS NULL;
https://www.cloudways.com/blog/how-to-join-two-tables-mysql/
This is pure set theory which you can achieve with the minus operation.
select id, name from table1
minus
select id, name from table2
Here's what worked best for me.
SELECT *
FROM #T1
EXCEPT
SELECT a.*
FROM #T1 a
JOIN #T2 b ON a.ID = b.ID
This was more than twice as fast as any other method I tried.
Watch out for pitfalls. If the field Name in Table1 contain Nulls you are in for surprises.
Better is:
SELECT name
FROM table2
WHERE name NOT IN
(SELECT ISNULL(name ,'')
FROM table1)
You can use EXCEPT in mssql or MINUS in oracle, they are identical according to :
http://blog.sqlauthority.com/2008/08/07/sql-server-except-clause-in-sql-server-is-similar-to-minus-clause-in-oracle/
That work sharp for me
SELECT *
FROM [dbo].[table1] t1
LEFT JOIN [dbo].[table2] t2 ON t1.[t1_ID] = t2.[t2_ID]
WHERE t2.[t2_ID] IS NULL
You can use following query structure :
SELECT t1.name FROM table1 t1 JOIN table2 t2 ON t2.fk_id != t1.id;
table1 :
id
name
1
Amit
2
Sagar
table2 :
id
fk_id
email
1
1
amit#ma.com
Output:
name
Sagar
All the above queries are incredibly slow on big tables. A change of strategy is needed. Here there is the code I used for a DB of mine, you can transliterate changing the fields and table names.
This is the strategy: you create two implicit temporary tables and make a union of them.
The first temporary table comes from a selection of all the rows of the first original table the fields of which you wanna control that are NOT present in the second original table.
The second implicit temporary table contains all the rows of the two original tables that have a match on identical values of the column/field you wanna control.
The result of the union is a table that has more than one row with the same control field value in case there is a match for that value on the two original tables (one coming from the first select, the second coming from the second select) and just one row with the control column value in case of the value of the first original table not matching any value of the second original table.
You group and count. When the count is 1 there is not match and, finally, you select just the rows with the count equal to 1.
Seems not elegant, but it is orders of magnitude faster than all the above solutions.
IMPORTANT NOTE: enable the INDEX on the columns to be checked.
SELECT name, source, id
FROM
(
SELECT name, "active_ingredients" as source, active_ingredients.id as id
FROM active_ingredients
UNION ALL
SELECT active_ingredients.name as name, "UNII_database" as source, temp_active_ingredients_aliases.id as id
FROM active_ingredients
INNER JOIN temp_active_ingredients_aliases ON temp_active_ingredients_aliases.alias_name = active_ingredients.name
) tbl
GROUP BY name
HAVING count(*) = 1
ORDER BY name
See query:
SELECT * FROM Table1 WHERE
id NOT IN (SELECT
e.id
FROM
Table1 e
INNER JOIN
Table2 s ON e.id = s.id);
Conceptually would be: Fetching the matching records in subquery and then in main query fetching the records which are not in subquery.
First define alias of table like t1 and t2.
After that get record of second table.
After that match that record using where condition:
SELECT name FROM table2 as t2
WHERE NOT EXISTS (SELECT * FROM table1 as t1 WHERE t1.name = t2.name)
I'm going to repost (since I'm not cool enough yet to comment) in the correct answer....in case anyone else thought it needed better explaining.
SELECT temp_table_1.name
FROM original_table_1 temp_table_1
LEFT JOIN original_table_2 temp_table_2 ON temp_table_2.name = temp_table_1.name
WHERE temp_table_2.name IS NULL
And I've seen syntax in FROM needing commas between table names in mySQL but in sqlLite it seemed to prefer the space.
The bottom line is when you use bad variable names it leaves questions. My variables should make more sense. And someone should explain why we need a comma or no comma.
I tried all solutions above but they did not work in my case. The following query worked for me.
SELECT NAME
FROM table_1
WHERE NAME NOT IN
(SELECT a.NAME
FROM table_1 AS a
LEFT JOIN table_2 AS b
ON a.NAME = b.NAME
WHERE any further condition);

Join SQL Tables with Unique Data (Not same number of columns!)

How can I join three or four SQL tables that DO NOT have an equal amount of rows while ensuring that there are no duplicates of a primary/foreign key?
Structure:
Table1: id, first_name, last_name, email
Table2: id (independent of id in table 1), name, location, table1_id, table2_id
Table3: id, name, location
I want all of the data from table 1, then all of the data from table 2 corresponding with the table1_id without duplicates.
Kind of tricky for a new guy...
Not sure what do you want to do with Table3.
A LEFT JOIN returns all records from the LEFT table, and the matched records from the right table. If there is no match (from the right side), then the result is NULL.
So per example:
SELECT * FROM Table1 AS t
LEFT JOIN Table2 AS tt
ON t.id = tt.id
The LEFT table refers to the table statement before the LEFT JOIN, and the RIGHT table refers to the table statement after the LEFT JOIN. If you want to add in Table3 as well, use the same logic:
SELECT * FROM Table1 AS t
LEFT JOIN Table2 AS tt
ON t.id = tt.id
LEFT JOIN Table3 AS ttt
ON t.id = ttt.id
Note, that I use alias names for the tables (by using AS), so that I can more easily refer to a specific table. For example, t refers to Table1, tt refers to Table2, and ttt refers to Table3.
Joins are often used in SQL, therefore it is useful to look into: INNER JOIN, RIGHT JOIN, FULL JOIN, and SELF JOIN, as well.
Hope this helps.
Good luck with learning!
You will want to use an LEFT JOIN
SELECT * FROM table1 LEFT JOIN table2 ON Table1.ID = Table2.table1_id

SQL statement selecting rows from a table dependent on information from another table

I have two different tables in a database, differing in number of columns. Now, I want to select a number of rows from the first table dependent on some variable (for example that the first column should have the value 1). However, I would also like to use information from my other table to select rows from my first table.
In my specific case, both table1 and table2contains the columns Group and Person. Table1 specify each person once, and declares what group he or she belongs to. However, people can also be part of secondary groups, which are listed in table2. That is, in table2, a person can be listed again with a new group number.
I would like to write an SQL statement where I select persons (that is, rows) from table1 (since I have more information about the persons in this table) that are members of a certain group, x. However, since a person can belong to several groups, I need to look through table2 as well, somehow.
How can I write this SQL statement?
select t1.person_id,t1.group_id
from table1
union all
select t2.person_id,t2.group_id
from table2
this will give you one table
person group
person1 group1
person1 group2
person2 group3
no matter what tables they belong to.
This architecture seems silly however if the same data is in both tables.
If i have understood your question correctly, this query below will get you a person's details where the person is a member of a group 'X' and that relationship between person and that particular group 'X'is coming from a record maintained in either table1 or table2.
SELECT t1.*
FROM table1 t1
LEFT OUTER JOIN table2 t2
ON t1.Person = t2.Person
WHERE t1.Person = 'Y'
AND (t1.Group = 'X' OR t2.Group = 'X')
You will need some sort of identifier in both tables - like a candidate key.
When you do your select you need to join the tables, example:
SELECT column_name(s)
FROM Table1 table_name1
INNER JOIN Table2 table_name2
ON table_name1.column_name=table_name2.column_name
WHERE table_name1.person = table_name2.person
You can use JOIN clause to combine rows from two or more tables, based on a related column between them.
Let's look at a selection in this example:
SELECT
       table1.user_name,
       table2.group_name,
       table1.address
FROM table1
INNER JOIN table2
ON table1.UserID = table2.ID;

Help with Joins

my first table has about 18K records
so when i
select * from table2 i get about 18k
i'm trying to do a join on it as follows, but i'm getting like 26K back.. what am i doing wrong? i though it's supposed to return all of the "right" aka table2 records plus show me whatever value matches from the first in a separate column...
Select t1.fID , t2.*
FROM table1 t1 right join table2 t2 on t1.fName = t2.f
here is an exmaple of my tables:
table 1:
fID, fName
table 2: id, f, address, etc
i need to get all records from table 2, with an fID column, whenever f=fName
table1 has many rows with a value of fname that matches the same in table2.
Example, say 5k rows table2 have no matching rows in table1, you have a average of 2 rows in table 1 for each of the remaining 13k table2 rows
Because you have also asked for a column for table1, this will happen. You'll note multiple t1.fId values for a given t2.fname. Or NULLs
If t1.fName and t2.f aren't unique identifiers for their tables, you will find that rows from table1 are being joined with multiple rows from table2.
The RIGHT JOIN keyword Return all rows from the right table (table_name2), even if there are no matches in the left table (table_name1).See Right Join
So it looks like you do not have your matching criteria set correctly or you have no matches.
This is possible when some fName values are repeated in Table2 and/or Table 1.
Run these Queries and See:
SELECT fName, COUNT(1) FROM Table2 GROUP BY fName HAVING COUNT(1) > 1
SELECT fName, COUNT(1) FROM Table1 GROUP BY fName HAVING COUNT(1) > 1