Cartesian join with multple outer joins to common root - mysql

I have the following schema.
I can run two queries fairly simply
select * from booking_model_assignment
join booking_model on booking_model_assignment.booking_model_id = booking_model.id
left outer join axis_channel_mappings on bmi_id = axis_channel_mappings.assignment_id
left outer join axis_revenue_stream_mappings on bmi_id = axis_revenue_stream_mappings.assignment_id
which will give me all of the combinations of channel mappings and 'revenue_stream_mappings' which fit a booking model, with Null if there is one which only matches in one of the tables.
The other query
select * from axis_channel join axis_revenue_stream
Gives all of the possible combinations of channels and revenue streams.
What I would like is a query which will give all of the combinations, and the booking_model if that combination matches.
Any time I try to join or subquery I seem to get too many, or too few results. I think the issue is that I want the assignment_id to match across outer joins but only if there is an outer join.
The schema is laid out like this so it will be possible to add new axis and fit models to combinations, so if there is an easier way to achieve this I would be open to changing the schema.
EDIT
I have a partial solution based on Eggyal's answer but it is not extendable.
SELECT c.*, r.*, GROUP_CONCAT(a.bmi_id), GROUP_CONCAT(b.name) AS booking_models
FROM axis_channel c
CROSS JOIN axis_revenue_stream r
LEFT JOIN axis_channel_mappings cm ON cm.channel_id = c.id
LEFT JOIN axis_revenue_stream_mappings rm ON rm.revenue_stream_id = r.id
LEFT JOIN booking_model_assignment a ON (a.bmi_id = cm.assignment_id
AND a.bmi_id = rm.assignment_id)
OR (a.bmi_id = cm.assignment_id
AND rm.assignment_id IS NULL)
OR (cm.assignment_id IS NULL
AND a.bmi_id = cm.assignment_id)
LEFT JOIN booking_model b ON b.id = a.booking_model_id
GROUP BY c.id, r.id
But if I were to add more axes this query would grow way to cumbersome.

SELECT c.*, r.*, GROUP_CONCAT(b.name) AS booking_models
FROM axis_channel c
CROSS JOIN axis_revenue_stream r
LEFT JOIN axis_channel_mappings cm ON cm.channel_id = c.id
LEFT JOIN axis_revenue_stream_mappings rm ON rm.revenue_stream_id = r.id
LEFT JOIN booking_model_assignment a ON a.bmi_id = cm.assignment_id
AND a.bmi_id = rm.assignment_id
LEFT JOIN booking_model b ON b.id = a.booking_model_id
GROUP BY c.id, r.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'

In MySQL JOIN means which join perform..?

It's to confusing, I have query where I have write JOIN with multiple table then which type of join it'll perform..?
For example :
SELECT
b.*
FROM
tbl_bookings b
JOIN tbl_users ua ON ua.id = b.act_id
JOIN tbl_users uc ON uc.id = b.cust_id
JOIN tbl_venue v ON b.venue_id = v.venue_id
WHERE
b.act_id = 4
Can any one please let me know by which type of join it'll perform..?
JOIN equals to an INNER JOIN . They are functionally equivalent, but INNER JOIN can be a bit clearer to read, especially if the query contains other type of JOIN
For something other than INNER JOIN you should specify the join you want.
LEFT JOIN / RIGHT JOIN which are the same as LEFT OUTER JOIN and RIGHT OUTER JOIN .
Those are just different ways of saying the same thing.
It will perform INNER JOIN. It is good to write INNER JOIN when you have different types of joins in query.

Fetching a price with INNER JOIN using 3 different variables

What I have been trying to achieve is to pull a price based on 3 different variables: brand_id, model_id, motor_id.
The design of the tables that I am working with:
The only issue is that when I add an INNER JOIN for databaseapp_lkp_prices I get a zero result set (fyi, there aren't any prices currently set so databaseapp_lkp_prices is an empty table)
I was expecting to see NULL in place of the price for the 48,000 records that exist when I don't add the databaseapp_lkp_prices INNER JOIN
My query is:
SELECT
a.brand,
b.model,
c.motor,
d.ecu_hardware_ver,
d.ecu_software_ver,
d.ecu_software_upg_ver,
d.ecu_brand,
d.ecu_type,
d.eprom,
d.eprom_desc,
d.`checksum`,
d.checksum16,
c.motor_hp * 1.2 AS motor_hp,
e.price,
c.motor_id,
c.model_id,
c.brand_id
FROM
databaseapp_brand AS a
INNER JOIN databaseapp_model AS b ON b.brand_id = a.brand_id
INNER JOIN databaseapp_motor AS c ON b.model_id = c.model_id
INNER JOIN databaseapp_ecu AS d ON d.motor_id = c.motor_id
INNER JOIN databaseapp_lkp_prices AS e ON c.brand_id = e.brand_id AND c.model_id = e.model_id AND c.motor_id = e.motor_id
ORDER BY
a.brand ASC,
b.model ASC
Anyone able to help me out with why I'm getting a zero result set when I try to look up the price.
Cheers!
Inner join requires match. No match no row. You should try LEFT JOIN instead of INNER JOIN for databaseapp_lkp_prices contribution.

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.

Inner join on four tables on MySQL

I am trying to do an inner join on four tables in MySQL. The table names are:
question (id_question, question_text, id_standard)
standard (id_standard, standardtext)
organisation_standard(id_organisation,id_organisation,id_standard)
organisation (id_organisation, organisation_name)
This is my query and it's giving me repetitive values:
select distinct a.question_text, d.organisation_name
from question a
inner join standard b on a.id_standard = b.id_standard
inner join organisation_standard c on b.id_standard= c.id_standard
inner join organisation d on c.id_organisation = d.id_organisation
where a.id_standard = 18;
How can I avoid the repetitive values?
What you need is a left join and not an inner join change the inner joins into left joins and you will get just one row:
select distinct
a.question_text, d.organisation_name
from
question a
left join
standard b ON a.id_standard = b.id_standard
left join
organisation_standard c ON b.id_standard = c.id_standard
left join
organisation d ON c.id_organisation = d.id_organisation
where
a.id_standard = 18
group by a.id_standard;
This diagram from another so answer gives the difference between the different joins