Show results of joined tables even if some values don't match - sql

Access Database
table contacts
--------------
id
surname
name
table relations
---------------
contact_id
relation_id
Both contact_id and relation_id are foreign keys referenced to table contacts' id
I want to execute a query to get both the contact's surname/name and the relation's surname/name if a relation for the current contact exist. If it doesn't exist I want to get the contact's surname/name and blank values for the relation's fields.
All this in one query
EDIT:
I used left join. I am running the query using VB.NET:
Dim myOleDbDataReader As OleDbDataReader = _
New OleDbCommand( _
"SELECT c.id AS contact_id " & _
" , c.surname AS contact_surname " & _
" , c.name AS contact_name " & _
" , c2.id AS related_id " & _
" , c2.surname AS related_surname " & _
" , c2.name AS related_name " & _
"FROM ((contacts c " & _
"LEFT JOIN relations r " & _
"ON c.id = r.contact_id) " & _
"INNER JOIN contacts c2 " & _
"ON c2.id = r.relation_id)" _
, connection).ExecuteReader()
I get OleDbException: Join expression not supported.
They say in another post that:
"Access won't let you use conventional joins in the where clause when you use LEFT/RIGHT/INNER JOINS in the FROM clause. It is probably intentional to get you to buy more expensive software." - ( Is the join expression not supported by MS Access? )
It is not exactly that. From some examples I tried I came to the conclusion that:
Access won't let you use outer joins (LEFT/RIGHT) together with one or more INNER JOINS.
What in John Carmack's name can I do?
I would like to avoid seperate select queries.
Please help...

SELECT c.id AS contact_id
, c.surname AS contact_surname
, c.name AS contact_name
, c2.id AS related_id
, c2.surname AS related_surname
, c2.name AS related_name
FROM contacts c
LEFT JOIN relations r
ON c.id = r.contact_id
JOIN contacts c2
ON r.relation_id = c2.id
The above does NOT work in MS-Access.
This is slightly different (two left joins) but it works:
SELECT c.id AS contact_id
, c.surname AS contact_surname
, c.name AS contact_name
, c2.id AS related_id
, c2.surname AS related_surname
, c2.name AS related_name
FROM contacts c
LEFT JOIN
( relations r
LEFT JOIN contacts AS c2
ON r.relation_id = c2.id
)
ON c.id = r.contact_id
Despite the second LEFT JOIN, it will give same result set, since the second LEFT JOIN involves a Foreign Key relationship (in the direction from many -> one).
To have a LEFT JOIN with an INNER JOIN you could use:
SELECT c.id AS contact_id
, c.surname AS contact_surname
, c.name AS contact_name
, g.id AS related_id
, g.surname AS related_surname
, g.name AS related_name
FROM contacts c
LEFT JOIN
( SELECT r.contact_id
, c2.id
, c2.surname
, c2.name
FROM relations r
INNER JOIN contacts AS c2
ON r.relation_id = c2.id
) AS g
ON c.id = g.contact_id

Related

Multiple joins into the same table (TSQL)

I'm needing rows from the Employee table that have null values in OwnerID field and GMID field.
SELECT b.FirstName + space(1) + b.LastName AS OwnerName,
c.FirstName + space(1) + c.LastName AS GeneralManager
FROM Store a
JOIN Employee b ON a.OwnerID = b.EmployeeID
JOIN Employee c ON a.GMID = c.EmployeeID
The query is working...but the store table has null values in the OwnerID and the GMID fields. What changes do I need to bring back the null rows also?
Update
This is the corrected query.
SELECT b.FirstName + space(1) + b.LastName AS OwnerName,
c.FirstName + space(1) + c.LastName AS GeneralManager
FROM Store a
LEFT JOIN Employee b ON a.OwnerID = b.EmployeeID
LEFT JOIN Employee c ON a.GMID = c.EmployeeID
https://learn.microsoft.com/en-us/sql/t-sql/queries/from-transact-sql?view=sql-server-2017
Use left join instead of join.
The LEFT JOIN keyword returns all records from the left table (table1), and the matched records from the right table (table2). The result is NULL from the right side, if there is no match.
Type of joins: See more here

How to avoid showing duplicate values in an inner join

I am trying not to show duplicate values in the ORDER column from the results list; however, I am showing duplicate "ORDER" values. How can I fix this?
select i.contractnumber as "CONTRACT NUMBER", t.ordernumber as
"ORDER", t.title as "ORDER TITLE", c.companyname as "COMPANY",
LEFT(cs.firstname, 1) +'. '+ cs.lastname as "TECHINICAN",
REPLACE(cs.CONTACT,'703-735-', 'x') as "CONTACT (703) 735....)"
from Company c inner join CONTRACTS i
on i.Company_ID = c.Company_ID
inner join Orders t
on t.ordernumberid = i.ordernumberid
inner join hub rut
on rut.titleOrder_ID = t.titleOrder_ID
inner join hub2 r
on r.Role_ID = rut.Role_ID
inner join Customer u
on u.Customer_ID = rut.Customer_ID
inner join CORD cs
on cs.CORD_ID = u.CORD_ID
inner join Method cv
on cv.Method_ID = i.Method_ID
where cs.Contact LIKE '%703-735-%'
and cv.Method_ID = 1;
The simple way to fix this is with a group by -- eg GROUP BY Order however if you have more than one value for the other columns you will have an issue -- you can pick a value -- for example max. That would like like this:
select
max(i.contractnumber) as "CONTRACT NUMBER",
t.ordernumber as "ORDER",
max(mat.title) as "ORDER TITLE",
max(c.companyname) as "COMPANY",
max(LEFT(cs.firstname, 1) +'. '+ cs.lastname) as "TECHINICAN",
max(REPLACE(cs.CONTACT,'703-735-', 'x')) as "CONTACT (703) 735....)"
-- etc as you have
-- ...
-- end with
GROUP BY t.ordernumber

Proper Syntax for 3 table SELECT query

I've got 3 tables:
tblPosts
tblComments
tblUsers
I'm trying to get a listing of Posts along with associated Comments. The tricky part seems to be getting the Posts and Comments to show the proper author (User). This is the closest I get but then the Posts authors are incorrect. I'm grouping my CFOutput on "pid", so I only get each post one time as I would expect.
SELECT tblPosts.pid
, tblPosts.title
, tblPosts.description
, tblPosts.price
, tblPosts.datecreated AS pdate
, tblPosts.image1
, tblComments.comment
, tblComments.datecreated AS cdate
, tblUsers.fname
, tblUsers.lname
FROM tblPosts
LEFT JOIN tblComments ON tblPosts.pid = tblComments.pid
LEFT JOIN tblUsers ON tblComments.uid = tblUsers.uid
Any thoughts?
Thanks!
Since both tables contain an author id, you must to JOIN to tblUser twice: once for posts and once for comments. That means you must use a table alias to differentiate between the two. Something along these lines, where pa is the alias for "Post Author" and ca the alias for "Comment Author".
SELECT p.pid
, p.title
, ...
, pa.fname AS PostAuthorFirstName
, pa.lname AS PostAuthorLastName
, ca.fname AS CommentAuthorFirstName
, ca.lname AS CommentAuthorLastName
FROM tblPosts p
LEFT JOIN tblUsers pa ON pa.uid = p.uid
LEFT JOIN tblComments c ON p.pid = c.pid
LEFT JOIN tblUsers ca ON ca.uid = c.uid
I'm not familiar with all the fields in you tables. Join the post to the users table as well to get the specific users for writing posts.
How about trying this:
SELECT p.pid
,p.title
,p.description
,p.price
,p.datecreated AS pdate
,p.image1
,c.comment
,c.datecreated AS cdate
,u1.fname AS CommentAuthorsName
,u1.lname AS CommentAuthorsLastName
,u2.fname AS PostAuthorName
,u2.lname AS PostAuthorLastName
FROM tblPosts p
LEFT JOIN tblComments c
ON p.pid = c.pid
LEFT JOIN tblUsers u1
ON c.uid = u1.uid
LEFT JOIN tblUsers u2
ON p.uid = u2.uid

join tables sql

I have the following tables
Dishes table:
Category table:
t_time table:
To get connect a dish with the ingredients I have the following code which works:
$sql = "SELECT d.name, i.item\n"
. "FROM dish d\n"
. "JOIN dish_ingredients di ON ( d.id = di.dish_id )\n"
. "JOIN ingredients i ON ( di.ingredient_id = i.id )\n"
. "WHERE d.id =1\n"
. "LIMIT 0 , 30";
but now I want to connect the dish with the matching categories/t_time and cuisine . instead of having time= 6 and Category 3 being displayed when I do the query I want it to display 60 and fish instead. What would be the easiest way to do this? a good tutorial might help as well.
just join the tables just like the way you are doing.
SELECT d.name, i.item,
c.category,
e.cuisine,
f.t_time
FROM dish d
INNER JOIN dish_ingredients di ON ( d.id = di.dish_id )
INNER JOIN ingredients i ON ( di.ingredient_id = i.id )
INNER JOIN categories c ON (d.category = c.id)
INNER JOIN cuisine e ON d.cuisine = e.id
INNER JOIN t_time f ON d.time = f.id
WHERE d.id =1
-- LIMIT 0 , 30
If it is possible that a dish can have nullable values on category, cuisine, and t_time, use LEFT JOIN instead of INNER JOIN. Basically, INNER JOIN displays row on which it has at least one match on the table on which you have joined while the LEFT JOIN displays even if it has no rows on the other table.
Try this:
SELECT d.name, i.item, cat.category, t.t_time, cu.cuisine
FROM dish d
INNER JOIN dish_ingredients di ON d.id = di.dish_id
INNER JOIN ingredients i ON di.ingredient_id = i.id
INNER JOIN category cat ON d.category = cat.id
INNER JOIN cuisine cu ON d.cuisine = cu.id
INNER JOIN t_time t ON d.t_time = t.id
WHERE d.id = 1
$sql = "SELECT d.name, i.item, c.category, t.t_time, cs.cuisine\n"
. "FROM dishes d\n"
. "JOIN dish_ingredients di ON ( d.id = di.dish_id )\n"
. "JOIN ingredients i ON ( di.ingredient_id = i.id )\n"
. "LEFT JOIN category c ON ( c.id = d.category )\n"
. "LEFT JOIN t_time t ON ( t.id = d.t_time )\n"
. "LEFT JOIN cuisine cs ON ( cs.id = d.cuisine)\n"
. "WHERE d.id =1\n"
. "LIMIT 0 , 30";
Try to join to the tables with LEFT JOIN, it will show the category,t_time and cuisine if it exists.

MS Access query problem

SELECT
tbl_vehicle_models.model_name AS Vehicle_Model,
tbl_vehicle_models.manufacturer AS Manufacturer,
tbl_jobs.vehicle_registration_number AS Registration_Number,
tbl_customers.first_name + " " + tbl_customers.last_name AS Customer_Name,
tbl_customers.address AS Address,
tbl_customers.contact_no AS Contact_Number,
tbl_jobs.cost_charged AS Cost,
tbl_jobs.was_accident AS Was_Accident,
tbl_jobs.was_towed AS Was_Towed,
tbl_jobs.job_call_time AS Call_Time,
tbl_jobs.job_arrival_time AS Arrival_Time,
tbl_jobs.job_leaving_scene_time AS Leaving_Time,
tbl_places.place_name AS Place
FROM
tbl_jobs
INNER JOIN tbl_vehicle_models
ON ( tbl_vehicle_models.ID = tbl_jobs.vehicle_model )
INNER JOIN tbl_customers
ON ( tbl_customers.ID = tbl_jobs.customer_id )
INNER JOIN tbl_places
ON ( tbl_places.ID = tbl_jobs.job_place )
What's wrong with this query? I am getting error saying missing operator in query expression '( v.ID = j.vehicle_model )
INNER JOIN tbl_customers c ON ( c.id = j.customer_id )
INNER JOIN tbl_places p ON ( p.ID = j.job_place'
Edit: This solved my problem:
SELECT tbl_vehicle_models.model_name, tbl_vehicle_models.manufacturer, tbl_jobs.vehicle_registration_number, tbl_customers.first_name & " " & tbl_customers.last_name AS Expr1, tbl_customers.address, tbl_customers.contact_no, tbl_jobs.cost_charged, tbl_jobs.was_accident, tbl_jobs.was_towed, tbl_jobs.job_call_time, tbl_jobs.job_arrival_time, tbl_jobs.job_leaving_scene_time, tbl_places.place_name
FROM ((tbl_jobs INNER JOIN tbl_vehicle_models ON tbl_jobs.vehicle_model = tbl_vehicle_models.ID) INNER JOIN tbl_customers ON tbl_jobs.customer_id = tbl_customers.ID) INNER JOIN tbl_places ON tbl_jobs.job_place = tbl_places.ID;
Are you sure that v.ID and j.vehicle_model have the same data type?
Looks like v.ID is an integer and j.vehicle_model a string
I think this problem happens when you try to use operators with incompatible operand data types.
EDIT:
Then, try changing
c.first_name + " " + c.last_name
to
c.first_name & " " & c.last_name
I think that's a problem with this concatenation
This solved my problem:
SELECT tbl_vehicle_models.model_name, tbl_vehicle_models.manufacturer,
tbl_jobs.vehicle_registration_number, tbl_customers.first_name & " " &
tbl_customers.last_name AS Expr1, tbl_customers.address, tbl_customers.contact_no,
tbl_jobs.cost_charged, tbl_jobs.was_accident, tbl_jobs.was_towed, tbl_jobs.job_call_time,
tbl_jobs.job_arrival_time, tbl_jobs.job_leaving_scene_time, tbl_places.place_name
FROM ((tbl_jobs
INNER JOIN tbl_vehicle_models ON tbl_jobs.vehicle_model = tbl_vehicle_models.ID)
INNER JOIN tbl_customers ON tbl_jobs.customer_id = tbl_customers.ID)
INNER JOIN tbl_places ON tbl_jobs.job_place = tbl_places.ID;