mySQL: Multi-column join on several tables part II - mysql

I am adding a 5th table to an existing join. The original query will always return a single row because the where clause specifies a unique ID. Here are the tables we are using:
Table 1
carid, catid, makeid, modelid, caryear
Table 2
makeid, makename
Table 3
modelid, modelname
Table 4
catid, catname
Table 5
id, caryear, makename, modelname
Here is the existing query I am using:
SELECT a.*, e.citympg, e.hwympg
FROM table1 a
JOIN table2 b on a.makeid=b.makeid
JOIN table3 c on a.modelid=c.modelid
JOIN table4 d on a.catid=d.catid
JOIN table5 e on b.makename = e.make
and c.modelname = e.model
and a.caryear = e.year
WHERE a.carid = $carid;
There are 2 issues that I need to solve -
When there is no match on table 5, it does not return any results. It would seem that I need to do some sort of left join or split the query and do a union.
When there is a match on table 5, it returns multiple rows. Since the criteria that would return a single row is not being used, I would settle for an average of citympg and hwympg.
Can both objectives be achieved with a single query? How?

Assuming I understand what you want correctly... This query will constrain the results from table5 to one row per combination of the join criteria, returning average city/hwy mpg.
SELECT a.*, e.citympg, e.hwympg
FROM table1 a
JOIN table2 b on a.makeid=b.makeid
JOIN table3 c on a.modelid=c.modelid
JOIN table4 d on a.catid=d.catid
LEFT JOIN (SELECT year, make, model,
AVG(citympg) as citympg,
AVG(hwympg) as hwympg
FROM table5
GROUP BY year, make, model) e on b.makename = e.make
and c.modelname = e.model
and a.caryear = e.year
WHERE a.carid = $carid;
Note that it will return NULL mpg values when no record in table5 exists.

The usual approach is to use correlated subqueries like this:
SELECT a.*
, (SELECT avg(e.citympg)
FROM table5 e
WHERE e.make = b.makename
AND e.model = c.modelname
AND e.year = a.caryear
) as citympg
, (SELECT avg(e.hwympg)
FROM table5 e
WHERE e.make = b.makename
AND e.model = c.modelname
AND e.year = a.caryear
) as hwympg
FROM table1 a
JOIN table2 b on a.makeid=b.makeid
JOIN table3 c on a.modelid=c.modelid
JOIN table4 d on a.catid=d.catid
WHERE a.carid = $carid

Related

Get records where a key occurs alongside all of a set of values

I have two tables table1 and table2. A third table, table3, relates these two tables such that every record in table3 is the primary key, a foreign key to table1, and a foreign key to table2.
I have a selection of table2, and want to find all records in table1 which have a corresponding record in table3 for each of the records selected form table2
Table1
a
b
c
Table2 Selection
1
2
3
Table3
fk1
fk2
a
1
a
2
b
1
b
2
b
3
c
2
c
3
c
4
In this example, I want to find record b but not record a or c
I can make a join with:
select *
from table3
inner join table1
inner join table2 on table3.fk1=table1.id and table3.fk2=table2.id
where *table2 selection criteria*
But that just gives me everything in one table, I don't know how to require that you match ALL members of the selection, instead of any member
select eveonline_evecharacter.*
from eveonline_evecharacter
inner join mechanicus_characterskillmap on eveonline_evecharacter.id = mechanicus_characterskillmap.character_id
inner join mechanicus_skill on mechanicus_skill.id = mechanicus_characterskillmap.skill_id
inner join mechanicus_blueprintskill on mechanicus_blueprintskill.skill_id = mechanicus_skill.id
inner join mechanicus_blueprintoutput on mechanicus_blueprintoutput.blueprint_id=mechanicus_blueprintskill.blueprint_id
inner join mechanicus_item on mechanicus_item.id = mechanicus_blueprintoutput.item_id
where mechanicus_item.name = "Small Trimark Armor Pump I"
group by eveonline_evecharacter.id
having count (*) = (select count(*) from mechanicus_skill
inner join mechanicus_blueprintskill on mechanicus_blueprintskill.skill_id = mechanicus_skill.id
inner join mechanicus_blueprintoutput on mechanicus_blueprintoutput.blueprint_id=mechanicus_blueprintskill.blueprint_id
inner join mechanicus_item on mechanicus_item.id = mechanicus_blueprintoutput.item_id
where mechanicus_item.name = "Small Trimark Armor Pump I");
Get the count of the joined rows and compare this with the count of all the rows in table 2.
SELECT t1.*
FROM table1 AS t1
JOIN table3 AS t3 ON t3.fk1 = t1.id
JOIN table2 AS t2 ON t3.fk2 = t2.id
WHERE *some condition on table 2*
GROUP BY t1.id
HAVING COUNT(*) = (
SELECT COUNT(*) FROM table2 WHERE *some condition on table 2*
)
This assumes that all the IDs in table1 and table2 are unique, and all the pairs are unique. If not, use HAVING COUNT(DISTINCT t1.id) = (SELECT COUNT(DISTINCT id) FROM table2).

join 3 tables if 3rd table does not have that value

Table 1
id , userid, eventid , name
table 2
eventid , zoneid , userid
table 3
eventid , userid, status
if all three table having the eventid means i dont want to select that record (i mean if table 3 have the eventid), else i need to select records
i tried my query
SELECT
*
FROM
`table1` c1
INNER JOIN `table2` c2 ON c2.eventid = c1.eventid
LEFT JOIN table3 c3 ON c3.eventid = c1.eventid
WHERE
c2.zoneid=2
AND c1.active='1'
GROUP BY
c1.eventid
Add a where clause where there is no c3:
SELECT *
FROM `table1` c1
INNER JOIN `table2` c2 ON c2.eventid = c1.eventid
LEFT JOIN table3 c3 ON c3.eventid = c1.eventid
WHERE c2.zoneid=2 AND c1.active='1'
AND c3.id IS NULL
group by c1.eventid
SELECT
*
FROM
`table1` c1
INNER JOIN `table2` c2 ON c2.eventid = c1.eventid
WHERE
c2.zoneid=2
AND c1.active='1'
AND NOT EXISTS (SELECT * FROM table3 c3 WHERE c3.eventid = c1.eventid)
GROUP BY
c1.eventid
Applying a WHERE-condition (like some of the other answers suggest) on a table that has been joined through a LEFT/RIGHT OUTER JOIN will actually make it a regular join.
The other examples that have been posted ask c1.eventid to equal c3.eventid, and c3.eventid to be NULL - good chance that the result will be not what you expect, depending on how the database treats c1.eventid = c3.eventid if both are NULL (I'd have to read up on that).
A Left join on the 3rd table and the condition WHERE C.eventid IS NULL should do the work.
SELECT *
FROM table1 A
INNER JOIN table2 B
ON A.eventid = B.eventid
LEFT OUTER JOIN table3 C
ON A.eventid = C.eventid
WHERE C.eventid IS NULL

Return zero or null when Joining 3 tables in mysql

I am trying to JOIN 3 Tables(table1, table2 & table3) in Mysql query where I want to pull the matching data from 2 tables(table1 & table2) comparing a Common Column existing in 3 tables(ie. 'PID').
When Joining these 3 tables, there is no data in table1 with the given Date('2012-12-27') then it's returning complete blank row.. Here, I want to get the matching data from the table2 matching the given Date and 'ZERO' or 'NULL' where there is no matching data in the other table ie. table1.. instead of a whole blank row.
Here is the code I was trying that returns a complete BLANK ROW..
SELECT * FROM table3 b
LEFT JOIN table1 r ON r.PID = b.PID
LEFT JOIN table2 a ON ab.PID = b.PID
WHERE b.Name ='stallion' AND r.Date = '2012-12-27' AND a.Date = '2012-12-27'
;
Use two different JOIN statement then UNION them.
The rows where there is no data in table1 (r) have r.Data = NULL and are therefore filtered away by your WHERE condition. You need to add OR r.Date IS NULL to your WHERE condition or move the condition to the ON clause:
SELECT * FROM table3 b
LEFT JOIN table1 r ON r.PID = b.PID AND r.Date = '2012-12-27'
LEFT JOIN table2 a ON a.PID = b.PID AND a.Date = '2012-12-27'
WHERE b.Name ='stallion';

Get distinct value from join query (Join Table)

How get a distinct value form more than one table (inner join query).
Eg,
select a.id,b.name,c.address
from table1 a
inner join table2 b on (a.id = b.row_id)
inner join table3 c on (a.id = c.ticket_id)
where c.status = 'open';
Here the scenario is for example, two rows contain the same a.id value so how to get the distinct value from a.id.
Somebody help me that how to get?
just add Distinct ...
select DISTINCT a.id,b.name,c.address
from table1 a
inner join table2 b on (a.id = b.row_id)
inner join table3 c on (a.id = c.ticket_id)
where c.status = 'open';
i think this is works fine..
if you need only one record distinct then it should be like this...
SELECT DISTINCT(cat_id) FROM PRODUCTS WHERE brand_id = 'sony'

MySQL syntax for JOIN depending on condition

What would be a syntax of the following query:
Get all columns from Table1 and JOIN Table2 if matching reference (Table1ID) exists, otherwise JOIN Table3.
Simplified DB structure is more or less as below
Table1
ID Type
1 std
Table2
ID Table1ID Title Language
1 1 Test en
Table3
ID Table1ID Title Language Flag
1 1 Other en 1
Also, I now realized that Table3 will have multiple entries that refer to single Table1.id. How to limit it to return only the latest entry (with highest id) for every result?
If you don't want an entire separate set of columns for each join, this may be what you're looking for:
SELECT *
FROM (
SELECT a.ID AS Table1ID, a.Type, b.ID, b.Title, b.Language, NULL AS Flag
FROM Table1 a
JOIN Table2 b ON a.ID = b.Table1ID
UNION ALL
SELECT a.ID, a.Type, c.ID, c.Title, c.Language, c.Flag
FROM Table1 a
LEFT JOIN Table2 b ON a.ID = b.Table1ID
JOIN Table3 c ON a.ID = c.Table1ID
JOIN (
SELECT MAX(id) AS maxid
FROM Table3
GROUP BY Table1ID
) d ON c.ID = d.maxid
WHERE b.ID IS NULL
) a
ORDER BY a.Table1ID
SQLFiddle Demo
this is one way to do it.
select table1.id, table1.type, ifnull(table2.title, table3.title)
from table1
left join table2 on table1.id = table2.table1ID
left join table3 on table1.id = table3.table1ID