MySQL LEFT OUTER JOIN not giving correct value - mysql

I have the following tables and relationships
Here are the sample data -
I tried the following query-
SELECT project.*, SUM(schedule.amount) as sch_total, SUM(expense.amount) as expense_total, SUM(bill.amount) as bill_total from project
LEFT OUTER JOIN schedule on project.project_id = schedule.project_id
LEFT OUTER JOIN site on project.project_id = site.project_id
LEFT OUTER JOIN expense on site.site_id = expense.site_id
LEFT OUTER JOIN bill on site.site_id = bill.site_id
GROUP BY project.project_id
This is the query result -
But "bill_total" should be 200, not 400.
What did I miss in the query?

Your expense table have multiple rows for same Id. That table must be aggregated first and then used in join -
SELECT project.*,
SUM(schedule.amount) as sch_total,
SUM(E.amount) as expense_total,
SUM(bill.amount) as bill_total
FROM project
LEFT OUTER JOIN schedule on project.project_id = schedule.project_id
LEFT OUTER JOIN site on project.project_id = site.project_id
LEFT OUTER JOIN (SELECT site_id, SUM(expense.amount)amount
FROM expense
GROUP BY site_id) E on site.site_id = expense.site_id
LEFT OUTER JOIN bill on site.site_id = bill.site_id
GROUP BY project.project_id

Related

MySQL Left Join returning unrelated records despite using IS NOT NULL

The following query with left joins returns records that do not have a match on the final left join, i.e. the assessment column is null, though I have the query with IS NOT NULL .
How should the query be changed to get just the matching records?
Basically I want to return unit_outcome records GROUPED according to related assessments in the lookup table.
DB Fiddle for LEFT JOIN showing records with null for assessment
SELECT *
FROM unit
left JOIN unit_unit_outcome_lookup
ON unit_unit_outcome_lookup.unit_fk = unit.unit_pk
left JOIN unit_outcome
ON unit_outcome.unit_outcome_pk = unit_unit_outcome_lookup.unit_outcome_fk
left JOIN unit_outcome_assessment_lookup
ON unit_outcome_assessment_lookup.unit_outcome_fk = unit_outcome.unit_outcome_pk IS NOT NULL
left JOIN assessment
ON assessment.assessment_pk = unit_outcome_assessment_lookup.assessment_fk IS NOT NULL
AND unit.unit_pk ='1'
DB Fiddle for INNER JOIN with no null records - how to group unit_outcomes by assessment?
SELECT MAX((unit.unit_pk)) AS unit_pk,
GROUP_CONCAT(unit_outcome.unit_outcome) unit_outcomes,
MAX(assessment.assessment) assessment,
GROUP_CONCAT(unit_outcome.unit_outcome_pk) unit_outcome_pks,
assessment.assessment_pk
FROM unit
INNER JOIN unit_unit_outcome_lookup
ON unit_unit_outcome_lookup.unit_fk = unit.unit_pk
INNER JOIN unit_outcome
ON unit_outcome.unit_outcome_pk = unit_unit_outcome_lookup.unit_outcome_fk
INNER JOIN unit_outcome_assessment_lookup
ON unit_outcome_assessment_lookup.unit_outcome_fk = unit_outcome.unit_outcome_pk
INNER JOIN assessment
ON assessment.assessment_pk = unit_outcome_assessment_lookup.assessment_fk
AND unit.unit_pk ='1'
GROUP BY assessment_pk;
fiddle
PS. Details can be found in the comments to the question.
The problem is this one,
unit_outcome_assessment_lookup.unit_outcome_fk = unit_outcome.unit_outcome_pk IS NOT NULL
If you want to select only what is existing on the other table use INNER JOIN or JOIN. Lets understand how join works: https://www.w3schools.com/sql/sql_join.asp.
Also use ALIAS on tables to make the query easier to read.
SELECT *
FROM unit u
LEFT JOIN unit_unit_outcome_lookup uuol ON uuol.unit_fk = u.unit_pk
LEFT JOIN unit_outcome uo ON uo.unit_outcome_pk = uuol.unit_outcome_fk
JOIN unit_outcome_assessment_lookup uoal ON uoal.unit_outcome_fk = uo.unit_outcome_pk
JOIN assessment a ON a.assessment_pk = uoal.assessment_fk
WHERE u.unit_pk ='1'

MS Access 2013 SQL Query LEFT JOIN

FROM (((Project
INNER JOIN MDS ON Project.PID=MDS.PID)
INNER JOIN PLocation ON Project.PID = PLocation.PID)
INNER JOIN Site ON PLocation.ACode = Site.ACode) AS [Prim]
LEFT JOIN ((Procurement INNER JOIN MagicT ON Procurement.PRNum = MagicT.PRNum)
INNER JOIN DO ON DO.DoNum = MagicT.DONum) AS [Prim2] ON Prim.PRNum = Prim2.PRNum
Hey guys. So the above from statement is giving me an error:
Syntax error in from clause
Funny thing is when I make the LEFT JOIN an INNER JOIN it runs fine, but sadly that isn't what I want. I read that I had to rename the inner queries and join them using their new names but unfortunately I do not think I did it properly.
Maybe this... using two inline views. but you should be able to do this with just ()'s in Access... however if you have same named columns in each of Prim/prim2 tables, this will present with errors you may have to spell out each of the column names needed in the inline views.
FROM (SELECT * FROM Project
INNER JOIN MDS ON Project.PID=MDS.PID
INNER JOIN PLocation ON Project.PID = PLocation.PID
INNER JOIN Site ON PLocation.ACode = Site.ACode) PRIM
LEFT JOIN (SELECT * from Procurement
INNER JOIN MagicT ON Procurement.PRNum = MagicT.PRNum
INNER JOIN DO ON DO.DoNum = MagicT.DONum) PRIM2
ON Prim.PRNUM = Prim2.PRNUM
--- maybe... in access the ()'s will handle the outer join but I don't know what table PRNUM is sourced from in (project, mds, plocation,site) so project is a guess...
FROM Project
INNER JOIN MDS ON Project.PID=MDS.PID
INNER JOIN PLocation ON Project.PID = PLocation.PID
INNER JOIN Site ON PLocation.ACode = Site.ACode
LEFT JOIN (SELECT * from Procurement
INNER JOIN MagicT ON Procurement.PRNum = MagicT.PRNum
INNER JOIN DO ON DO.DoNum = MagicT.DONum) PRIM2
ON Project.PRNUM = Prim2.PRNUM
You basically have
FROM Subquery1 LEFT JOIN Subquery2
but your subqueries don't have SELECT in them.
I think it should be:
FROM
(SELECT Prim.PRNum FROM
(((Project
INNER JOIN MDS ON Project.PID=MDS.PID)
INNER JOIN PLocation ON Project.PID = PLocation.PID)
INNER JOIN Site ON PLocation.ACode = Site.ACode)
AS [Prim])
LEFT JOIN
(SELECT Prim2.PRNum FROM
((Procurement INNER JOIN MagicT ON Procurement.PRNum = MagicT.PRNum)
INNER JOIN DO ON DO.DoNum = MagicT.DONum)
AS [Prim2])
ON Prim.PRNum = Prim2.PRNum
(edit: a little too late...)
I have also discovered one of my issues here, is that in Access, you can have a left or right join nested inside an inner join but CANNOT have an inner join inside a left or right join. Rewriting the query to not include these joins inside the inner joins has solved the issue.
Thank you for all the help.

Correct Join Query for SQL Query

I currently have the following Query
SELECT * FROM tbl_Cars c
INNER JOIN tbl_Car_Parts cp ON c.Id = cp.Id
INNER JOIN tbl_Car_Factory cf ON cp.Id = cf.Id
However I have now realised that there are some Ids which are in the Cars Table which are then not in the Car Parts table so these are being omitted from my results while I want them included. I tried changing my INNER JOIN to a LEFT OUTER JOIN but it made no difference in the result set I am returned?
Use LEFT OUTER JOIN in both of the joins.
SELECT * FROM tbl_Cars c
LEFT OUTER JOIN tbl_Car_Parts cp ON c.Id = cp.Id
LEFT OUTER JOIN tbl_Car_Factory cf ON cp.Id = cf.Id
Otherwise the second INNER JOIN will invalidate your first LEFT OUTER JOIN for those records that does not have ID (does not join) in the tbl_Car_Parts table.
After a LEFT OUTER JOIN you may be only use again INNER JOIN if the table you are joining is not related with the previous ones that are joined using the LEFT OUTER JOIN.
LEFT JOIN should have definitely solved your problem, Not sure why it didnt work.
Just to be safe I used Left join on both the tables...
SELECT * FROM tbl_Cars c
LEFT JOIN tbl_Car_Parts cp ON c.Id = cp.Id
LEFT JOIN tbl_Car_Factory cf ON cp.Id = cf.Id

mysql select statement not returning rows where some tables in query aren't populated

I'm having a real mind blank - This code selects rows quite nicely apart from those entries where I change st.station_id from a value of '1' to a different (but still valid) number but where there are no entries for that station_id in either the station_owner_map table, the organisation table or the cap_gen_data_table. I basically need to amend my sql to ignore any table where there are no entries.
Select st.station_id, st.station_name , st.st_town, st.st_state, c1.country_name, o1.organisation_name, som1.equity, st.river_basin, st.cost, st.cost_ref, st.comm_year,cg1.caporgen, ht1.hydro_name, cg1.value, srs1.srs_description, cg1.ref_year
FROM station st
inner join station_country_map scm1 on st.station_id = scm1.station_id
inner join country c1 on scm1.country_id = c1.country_id
inner join station_owner_map som1 on st.station_id = som1.station_id
inner join organisation o1 on som1.owner_id = o1.org_id
inner join cap_gen_data cg1 on st.station_id = cg1.station_id
inner join value_lookup vl1 on cg1.caporgen = vl1.id
inner join hydro_type ht1 on cg1.hydro_type_id = ht1.type_id
inner join station_record_status srs1 on cg1.capacity_status = srs1.st_rec_stat_id
where st.station_id = 1
It's caused by your inner joins. Inner join means there has to be a value in both tables for the record to show up in the result set.
Use left join instead, then only the table 'on the left' has to have a value.
Use left join on tables where the value may not be present.
If you have two tables A and B an inner join will only return the rows from A where the join condition is met. A left join will return all rows from A regardless of if the join condition is satisfied. Columns in the select statement associated with B will be null when a left join is used.
I have only added the left join to the tables you have indicated. If other tables may not satisfy the join condition change the join type from inner to left.
Select st.station_id, st.station_name , st.st_town, st.st_state, c1.country_name, o1.organisation_name, som1.equity, st.river_basin, st.cost, st.cost_ref, st.comm_year,cg1.caporgen, ht1.hydro_name, cg1.value, srs1.srs_description, cg1.ref_year
FROM station st
inner join station_country_map scm1 on st.station_id = scm1.station_id
inner join country c1 on scm1.country_id = c1.country_id
left join station_owner_map som1 on st.station_id = som1.station_id
left join organisation o1 on som1.owner_id = o1.org_id
left join cap_gen_data cg1 on st.station_id = cg1.station_id
inner join value_lookup vl1 on cg1.caporgen = vl1.id
inner join hydro_type ht1 on cg1.hydro_type_id = ht1.type_id
inner join station_record_status srs1 on cg1.capacity_status = srs1.st_rec_stat_id
where st.station_id = 1

Left outer join in access?

Following query does not work in access.
SELECT Fields.FieldId, PrecisionSettings.DecimalPlaces
from Fields left outer join FieldGroup on Fields.FieldGroupId = FieldGroup.FieldGroupId
left outer join Category on FieldGroup.CategoryId = Category.CategoryId
left outer join PrecisionSettings on
Category.InputAttributesID=PrecisionSettings.AttributesID
It gives error as missing operator in query expression.
In Access you can only join two results at a time. To join more tables you need more parentheses:
SELECT
Fields.FieldId,
PrecisionSettings.DecimalPlaces
FROM
(
(
Fields
LEFT OUTER JOIN FieldGroup ON Fields.FieldGroupId = FieldGroup.FieldGroupId
)
LEFT OUTER JOIN Category ON FieldGroup.CategoryId = Category.CategoryId
)
LEFT OUTER JOIN PrecisionSettings ON Category.InputAttributesID = PrecisionSettings.AttributesID