I have 3 tables, cars, cars_owner and owner.
I want to have the complete list of cars, those that do have owners and those that don't.
When a car has an owner, I must have the data of the owner.
Wrong query 1 (selects ownerless cars out):
SELECT * FROM car
LEFT JOIN cars_owner ON ...
INNER JOIN owner ON ...
Wrong query 2 (selects cars_owner relations without owners too):
SELECT * FROM car
LEFT JOIN cars_owner ON ...
LEFT JOIN owner ON ...
How do I left join a table with an inner join in MySQL?
This Query returns the cars that have owners:
SELECT * FROM car
LEFT JOIN cars_owner ON (car.CarID=cars_owner.CarID)
inner join owner ON (owner.OwnID = cars_owner.OwnID)
However this returns the cars without owners:
SELECT * FROM car
where (car.CarID!=(SELECT car.CarID FROM car
LEFT JOIN cars_owner ON (car.CarID=cars_owner.CarID)
inner join owner ON (owner.OwnID = cars_owner.OwnID)) )
You just need to nest the JOINs correctly:
SELECT * FROM car
LEFT JOIN (cars_owner INNER JOIN owner ON cars_owner.owner_id = owner.owner_id
) ON car.car_id = cars_owner.car_id
The point is that you want all cars (so a left join on cars_owner), but only cars_owner that have an existing owner (so an inner join on owner).
The brackets make sure that the inner join is executed first. That is: Give me all cars, and from those car_owners that have an actual owner, show the owners (otherwise show them as NULL, but don't discard the whole car row).
Related
I have four tables, Photo, Event, News, Spot and Photo is the table i want to check for records with relations to other tables.
Photo has the following sructure:
id
rel_model -> one of "news", "spot" and "event"
rel_id -> id of the related record in rel_model table
...
Tables other than Photo are constantly updated and some of the records ar deleted. I want to filter the photos to get the records that are related to existing records on other tables.
I tried the following
select
count(*)
from
Photo
inner join Event ON (rel_id = Event.id and rel_model="event")
inner join News ON (rel_id = News.id and rel_model="news")
inner join Spot ON (rel_id = Spot.id and rel_model="spot");
but I get 0 results where trying it with only one inner join works for checking against single table
select
count(*)
from
Photo
inner join Event ON (rel_id = Event.id and rel_model="event") ;
I need to add some and-or logic inbetween inner joins, bit could not figure out how.
How can I fetch the photos that still have unbroken relations to other tables?
you could use this query
select
count(*)
from Photo as P
where
P.rel_model = "event" and P.rel_id in (select T.id from Event as T) or
P.rel_model = "news" and P.rel_id in (select T.id from News as T) or
P.rel_model = "spot" and P.rel_id in (select T.id from Spot as T)
If you want to change your query, you should use left outer join:
select
count(*)
from Photo as P
left outer join Event ON (rel_id = Event.id and rel_model="event")
left outer join News ON (rel_id = News.id and rel_model="news")
left outer join Spot ON (rel_id = Spot.id and rel_model="spot")
where News.id is not null or Spot.id is not null or Event.id is not null
Your query return null rows because you trying to join same row with all three tables, but you join condition is matched only one, so other two inner joins eliminate you row.
You can do this using outer joins. With the inner joins you are losing a row when rel_id fails to match any of the three (and presumably, it matches only one of them, so you lose all rows). Then, you need to count each one separately:
select count(Event.id) + count(News.id) + count(Spot.id)
from Photo p left join
Event
ON p.rel_id = Event.id and rel_model="event" left join
News
ON p.rel_id = News.id and rel_model="news" left join
Spot
ON p.rel_id = Spot.id and rel_model="spot";
I have two tables, one with names of teams, the other holds various selections made by users, each of which is represented by the team's team_id. I want to be able to display the actual team names for each, but can't figure out how the join would work.
Table 1
user_id(int), selection1(int), selection2(int), selection3(int)
Table 2
team_id(int), team_name(varchar)
You need three joins:
select u.user_id, t1.team_name as team_name1, t2.team_name as team_name2,
t3.team_name as team_name3
from users u left outer join
teams t1
on u.selection1 = t1.team_id left outer join
teams t2
on u.selection2 = t2.team_id left outer join
teams t3
on u.selection3 = t3.team_id;
I have three tables People, Items and Locations. People can have only 1 Items. Locations has no relation to any of 2 tables. I want to get I record join all 3. I did 2 so far people + items but 3rd I keep getting MySQL errors. There's no JOIN ON for location. Any help?
SELECT * FROM ITEMS i
RIGHT JOIN PEOPLE p
ON (p.ITEM_ID =i.ID) where
p.ID=3
RIGHT JOIN
SELECT * FROM LOCATIONS lo where lo.ID=7
If there are no join keys in common, then you might want to do a cross join. This produces a Cartesian product, that is, every location for each row selected from People/items:
SELECT *
FROM ITEMS i RIGHT JOIN
PEOPLE p
ON (p.ITEM_ID =i.ID) cross join
location l
WHERE p.ID=3
By the way, MySQL has a very flexible (and non-standard) join syntax. You can actually leave the on clause off of a join and it will behave the same as a cross join. That is a bad habit, of course. If you want a cross join, then use cross join explicitly.
I'm assuming you want the location with the ID of 7 to appear on every row...
SELECT *
,(SELECT loc.name FROM Location loc WHERE loc.ID = 7) AS Location
FROM ITEMS i
RIGHT JOIN PEOPLE p
ON (p.ITEM_ID =i.ID)
WHERE p.ID=3
OR
SELECT *
FROM ITEMS i
RIGHT JOIN PEOPLE p
ON (p.ITEM_ID =i.ID)
CROSS JOIN (SELECT * FROM LOCATIONS lo where lo.ID=7) l
WHERE p.ID=3
OR
[several other ways to go about it]
Try something like this:
SELECT peo.id, it.id, loc.id
FROM People as peo
INNER JOIN Items as it on it.id = peo.id
INNER JOIN Locations as loc on loc.id = peo.id
WHERE peo.ID=3
Edit:
Your question was edited while I was typing this so my example doesn't match like it used to. Use ITEM_ID and ID as needed.
Although not recommended, you can also use
SELECT *
FROM People as peo
INNER JOIN Items as it on it.id = peo.id
INNER JOIN Locations as loc on loc.id = peo.id
WHERE peo.ID=3
this is my first post. I know that this is horribly inefficient and repetitive code that won't actually work, what I need to do is combine all these outputs into 1 select statement. I am obviously fairly new at this, but I've been at it all day and I just can't get started in the right direction, each snippet works on its own...please help!
Essentially I'm working with a DB with many tables, and to get the right data for each column, I often have to account for 3 tables with joins.
Thanks for any insight or help!
SELECT
Product.ProductID,
(
SELECT Abbreviation AS Country
FROM Product
LEFT JOIN ProductCountry
ON Product.ProductID = ProductCountry.ProductID
LEFT JOIN Location
ON ProductCountry.LocationID = Location.LocationID
GROUP BY Product.ProductID
),
(
SELECT r.ResourceName AS Manufacturer, rr.ResourceName AS Brand
FROM Product p
LEFT JOIN Resource r
ON p.ManufactureCode = r.ResourceID
INNER JOIN Resource rr
ON p.BrandCode = rr.ResourceID
),
Product.Name,
Product.UPC,
Product.Size,
(
SELECT Unit.abbreviation AS Measure
FROM Product
LEFT JOIN Unit
ON Product.Unit = Unit.UnitID
),
(
SELECT Category.ParentID AS Category, Category.Description AS Sub_Category
FROM Product
LEFT JOIN ProductCategory
ON Product.ProductID = ProductCategory.ProductID
LEFT JOIN Category
ON ProductCategory.CategoryID = Category.CategoryID
),
(
SELECT i.Description AS INGREDIENTS, i.MayContain AS Allergen_Statement
FROM Product
LEFT JOIN Ingredient i
ON Product.ProductID = i.IngredientID
),
(
SELECT GROUP_CONCAT( Special.Description SEPARATOR ', ' ) AS Free_From
FROM Product
LEFT JOIN ProductSpecial
ON Product.ProductID = ProductSpecial.ProductID
LEFT JOIN Special
ON ProductSpecial.SpecialID = Special.SpecialID
GROUP BY Product.ProductID
)
FROM Product, ProductStatus
WHERE ProductStatus.ProductStatusID = 1
First, some notes and assumptions...
I'm assuming the Country column is in the Location table, otherwise why would you bother joining it.
If you have trouble with this part, change the second join to a LEFT JOIN. I've had occasional trouble doing left join a to b followed by inner join b to c. I've found it's easier to keep the LEFT JOIN going, so my example left-joins both tables:
LEFT JOIN Resource r
ON p.ManufactureCode = r.ResourceID
INNER JOIN Resource rr
ON p.BrandCode = rr.ResourceID
You're joining to Resource in two different ways. That's completely OK with MySQL (and all the mainstream databases). You just have to alias one or both of the joins. I've aliased one of them:
LEFT JOIN Resource ON Product.ManufactureCode ...
LEFT JOIN Resource BrandResource ON Product.BrandCode...
I don't know from your example how ProductStatus is joined. You'll have to supply that.
Start small using the example below. Join in the Country, then when you've got that working, join in Manufacturer, then Brand, then Measure, etc. The query isn't doing a lot of advanced stuff; it's complicated mostly due to the sheer number of tables. Tackle them one at a time and you'll win :)
Finally, as #Bohemian noted in the comments, the GROUP BY can't be brought up to the top. Actually, it probably can, but it will complicate things beyond belief. I've left that as a subquery.
Here's the final result. Note that it's not tested because it's huge and I don't have table structures or sample data. But mostly because it's huge :) At any rate, this is meant as an example only.
SELECT
Product.ProductID,
Location.Country,
Resource.ResourceName AS Manufacturer,
BrandResource.ResourceName AS Brand,
Product.Name,
Product.UPC,
Product.Size,
Unit.Abbreviation AS Measure,
Category.ParentID AS Category,
Category.Description AS Sub_Category,
Ingredient.Description AS Ingredients,
Ingredient.MayContain AS Allergen_Statement,
(SELECT GROUP_CONCAT( Special.Description SEPARATOR ', ' ) AS Free_From
FROM Product
LEFT JOIN ProductSpecial
ON Product.ProductID = ProductSpecial.ProductID
LEFT JOIN Special
ON ProductSpecial.SpecialID = Special.SpecialID
GROUP BY Product.ProductID
)
FROM Product
INNER JOIN ProductStatus ON ... however it's joined
LEFT JOIN ProductCountry ON Product.ProductID = ProductCountry.ProductID
LEFT JOIN Location ON ProductCountry.LocationID = Location.LocationID
LEFT JOIN Resource ON Product.ManufactureCode = Resource.ResourceID
LEFT JOIN Resource BrandResource ON Product.BrandCode = BrandResource.ResourceID
LEFT JOIN Unit ON Product.Unit = Unit.UnitID
LEFT JOIN ProductCategory ON Product.ProductID = ProductCategory.ProductID
LEFT JOIN Category ON ProductCategory.CategoryID = Category.CategoryID
LEFT JOIN Ingredient ON Product.ProductID = i.IngredientID
WHERE ProductStatus.ProductStatusID = 1
Am I on completely the wrong tack ?
I want to do a left outer join to a query generated from 2 tables , but i keep getting errors. Do I need a different approach?
t1:
ID, Surname,Firstname
t2:
ID,JobNo,Confirmed
I have the following query:
SELECT JobNo AS N, StaffID AS P, Confirmed as C,
FirstName AS F,Surname AS S
FROM gigs_players, Players
WHERE t1.StaffID=t2.StaffID AND JobNo="2"
AND (`Confirmed` IS NULL OR Confirmed ='Y' )
ORDER BY Instrument,Surname
I want to add:
LEFT OUTER JOIN contacted (ON t1.StaffID=contact.ID AND t2.JobNo=contact.JobNo)"
Can I do a left outer join to a query generated from 2 tables ?
In order to use the t1 and t2 in the left outer join that you want to add you need to join them with the first tables, you can't reference them directly in the left outer join you, Something like the following:
SELECT JobNo AS N, StaffID AS P, Confirmed as C,
FirstName AS F,Surname AS S
FROM gigs_players, Players
Inner join t1 on ...
Inner join t2 on ...
LEFT OUTER JOIN contacted c
on t1.StaffID=c.ID AND t2.JobNo = c.JobNo
WHERE t1.StaffID=t2.StaffID AND JobNo="2"
AND (`Confirmed` IS NULL OR Confirmed ='Y' )
ORDER BY Instrument,Surname
So, based in your tables' structure, define the conditions of the two joins with t1 and t2 with other tables.
Here is the an example of a left join to a sub query. This might be what you are looking for.
select
parts.id,
min(inv2.id) as nextFIFOitemid
from test.parts
left join
( select
inventory.id,
coalesce(parts.id, 1) as partid
from test.inventory
left join test.parts
on (parts.id = inventory.partid)
) inv2
on (parts.id = inv2.partid)
group by parts.id;