I'm not really sure how to explain what I need to do without an example, so I hope I can explain myself well enough!
Lets say I have the following tables in my MySQL database:
buyers
sellers
adverts
addresses
locations
object_addresses
The tables buyers, sellers and adverts are all "objects". They are associated with addresses by object_addresses which has object_type, object_id and address_id.
The addresses table has a location_id to associate it with a location.
What I ultimately want is to select all types of objects that are within a certain distance (by using a latitude and longitude I have on the locations table).
I don't have a problem with the distance calculation itself. However, I am having trouble selecting all "objects" along with their respective addresses/ locations (since they all make use of object_address).
I am able to do the following:
SELECT * FROM buyers as b
INNER JOIN object_addresses as oa on oa.ObjectId = b.Id
INNER JOIN addresses as a on oa.AddressId = a.Id
INNER JOIN locations as l on a.LocationId = l.Id
WHERE oa.ObjectType = 'buyer';
I'm having a hard time incorporating sellers and adverts into the statement above.
This is likely an simple answer, but I just can't see it tonight. Can anyone point me in the right direction?
SELECT * FROM buyers as b
INNER JOIN object_addresses as oa on oa.ObjectId = b.Id
INNER JOIN addresses as a on oa.AddressId = a.Id
INNER JOIN locations as l on a.LocationId = l.Id
WHERE oa.ObjectType = 'buyer'
union
SELECT * FROM sellers as s
INNER JOIN object_addresses as oa on oa.ObjectId = s.Id
INNER JOIN addresses as a on oa.AddressId = a.Id
INNER JOIN locations as l on a.LocationId = l.Id
WHERE oa.ObjectType = 'seller'
etc?
if you don't like that - basically, you need to include the address bits multiple times - so that each one can be linked to each object type...
Try this one using join on specific conditions oa.ObjectType = 'seller',oa.ObjectType = 'advert',oa.ObjectType = 'buyer' so only related result set will join
SELECT * FROM buyers as b
INNER JOIN object_addresses as oa on (oa.ObjectId = b.Id AND oa.ObjectType = 'buyer')
INNER JOIN advert as ad on (oa.ObjectId = ad.Id AND oa.ObjectType = 'advert')
INNER JOIN seller as s on (oa.ObjectId = s.Id AND oa.ObjectType = 'seller')
INNER JOIN addresses as a on oa.AddressId = a.Id
INNER JOIN locations as l on a.LocationId = l.Id
Other solution would be join all your table and then check the object type
SELECT * FROM buyers as b
INNER JOIN object_addresses as oa on (oa.ObjectId = b.Id )
INNER JOIN advert as ad on (oa.ObjectId = ad.Id )
INNER JOIN seller as s on (oa.ObjectId = s.Id )
INNER JOIN addresses as a on oa.AddressId = a.Id
INNER JOIN locations as l on a.LocationId = l.Id
WHERE oa.ObjectType IN('buyer' , 'advert' , 'seller')
Related
I need to find all Users that belong to a certain Country (ID = 4321). But a User's Location can have...
EITHER a City
OR a Cityaddition, as you can see in...
The database schema:
User -< Locations >- City >- District >- Region >- Country
>- Cityaddition >- District >- Region >- Country
Legend: (read from left to right)
-< : "...has many..."
>- : "...has one..."
How do I have to modify my query below in order to make this EITHER-OR condition work in 1 single query?
(Currently, this query only selects Users that have BOTH a City AND a Cityaddition, which is never the case in reality.)
SELECT users.* FROM users
INNER JOIN locations ON locations.user_id = users.id
INNER JOIN cities ON cities.id = locations.city_id
INNER JOIN districts ON districts.id = cities.district_id
INNER JOIN regions ON regions.id = districts.region_id
INNER JOIN cityadditions ON cityadditions.id = locations.cityaddition_id
INNER JOIN districts
districts_cityadditions ON districts_cityadditions.id = cityadditions.district_id
INNER JOIN regions
regions_districts ON regions_districts.id = districts_cityadditions.region_id
WHERE (regions.country_id = 4321)
As a single query, you can do based on a parallel hierarchy and doing a logical NOT NULL on either side. Two separate via would be better as Barmar indicates due to the explicit OR.
Also, use aliases to shorten and make more readable and you can remove all those ticks. You typically only need those when dealing with column names that are also reserved words.
SELECT
u.*
FROM
users u
JOIN locations l
ON u.id = l.user_id
LEFT JOIN cities c
ON l.city_id = c.id
JOIN districts d
ON c.district_id = d.id
INNER JOIN regions r
ON d.region_id = r.id
AND r.country_id = 4321
LEFT JOIN cityadditions ca
ON l.cityaddition_id = ca.id
JOIN districts d2
ON ca.district_id = da.id
JOIN regions r2
ON d2.region_id = r2.id
AND r2.country_id = 4321
where
r.id IS NOT NULL
OR r2.id IS NOT NULL
Using UNION, but minimising code repetition, and the number of redundant joins...
The planner is also able to use indexing to minimise query cost
SELECT DISTINCT -- all queries MAY need this, depending on the structure of your data
`users`.*
FROM
`regions`
INNER JOIN
`districts`
ON `districts`.`region_id` = `regions`.`id`
INNER JOIN
(
SELECT
`locations`.`id`,
`cities`.`district_id`
FROM
`locations`
INNER JOIN
`cities`
ON `cities`.`id` = `locations`.`city_id`
UNION ALL
SELECT
`locations`.`id`,
`cityadditions`.`district_id`
FROM
`locations`
INNER JOIN
`cityadditions`
ON `cityadditions`.`id` = `locations`.`cityaddition_id`
)
AS `locations`
ON `locations`.`district_id` = `district`.`id`
INNER JOIN
`users`
ON `users`.`location_id` = `locations`.`id`
WHERE
`regions`.`country_id` = 4321
I have database structure as shown in the picture (it's simplified)
so now i want to calculate products in all stocks so that the result looked like (this assuming that store table has two records of store1 and store2):
if this is not possible this format is acceptable too
The main problem is that i can't figure out how should i calculate current stock for each store.
the curent stock for each stock = sum of all productin this stock
- sum of all productout this stock
+ sum of all producttransfer with transfertype=0 in this stock
- sum of all producttransfer with transfertype=1 in this stock
so how should i calculate it for each store when store number is not fixed
I think it should work, I'm writting it on the go so can't be 100% sure and there might be some typos
select A1.ProductID, A1.storehouseID, (SUM(IN)-SUM(OUT)) as quantity
from (
Select AD.productID, A.storehouseID, SUM(AD.Quantity) as IN
from actions A inner join productIN PI on A.ID = PI.ID
inner join actiondetails AD on PI.ID = AD.ID
group by AD.productID, A.storehouseID
UNION
select AD.ProductID, A.storehouseID, SUM(AD.Quantity)
from actions A inner join ProductTransfers T on A.ID = T.ID
inner join actiondetails AD on A.ID = AD.ID
where transferType = 0
group by AD.ProductID, A.storehouseID) as A1
inner join
(select AD.productID, A.storehouseID, SUM(AD.Quantity) as Out
from actions A inner join ProductOut PO on A.ID = PO.ID
inner join actiondetails AD on AD.ID = A.ID
group by AD.ProductID, A.storehouseID
UNION
select AD.productID, A.storehouse.ID, SUM(AD.Quantity) as Out
from actions A inner join ProductTransfers T on A.ID = T.ID
inner join actiondetails AD on AD.ID = A.ID
where TransferType = 1
group by AD.ProductID, A.storehouseID) as A2
on A1.ProductID = A2.ProductID and A1.storehouseID = A2.storehouseID
group by A1.ProductID, A1.StorehouseID
I have three tables Buildings, EnergyType and EnergyCategory. The first two are connected by a bridge table called build_types. The second two are connected by having related IDs (type_ID = cat_ID).
This join outputs buildings and every energy type they use:
SELECT B.building, E.energytype
FROM Buildings b
INNER JOIN build_types bt ON B.build_ID = bt.build_ID
INNER JOIN EnergyTypes e ON bt.type_ID = E.type_ID
ORDER BY B.building;
This join outputs the total number count of each energy type:
SELECT E.energytype, COUNT(*)
FROM Buildings b
LEFT JOIN build_types bt ON B.build_ID = bt.build_ID
LEFT JOIN EnergyTypes e ON bt.type_ID = E.type_ID
GROUP BY E.energytype;
I want a select statement that will return a table with building name on the left and energy category on the right, with only categories described that are 'Renewable'. I have:
SELECT B.building, E.energytype, E.energycategory
FROM Buildings b
INNER JOIN build_types bt ON B.build_ID = bt.build_ID
INNER JOIN EnergyTypes e ON bt.type_ID = E.type_ID
INNER JOIN EnergyCategories e ON E.cat_ID = E.type_ID
WHERE E.energycategory = 'Renewable';
but I get Error 1066: Not unique table/alias 'EnergyTypes'.
You have chosen the alias "E" for both EnergyTypes and EnergyCategories.
SELECT B.building, T.energytype, C.energycategory
FROM Buildings b
INNER JOIN build_types bt ON B.build_ID = bt.build_ID
INNER JOIN EnergyTypes T ON bt.type_ID = T.type_ID
INNER JOIN EnergyCategories C ON C.cat_ID = T.type_ID
WHERE C.energycategory = 'Renewable';
should work.
Change the alias for one of the tables. Make 'e' something else for one of them.
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
Is it possible to INNER JOIN a MySQL query to achieve this result?
I have a table with Strategies and a table with Members. The Strategy table holds the ID of the author that corresponds to their ID in the Member table and the ID of an author that updated the existing author's work. Is it possible to grab a reference to both of these people at the same time? Something like the following, which returns no errors, but also no results...
SELECT * FROM Strategies
INNER JOIN Members AS a
INNER JOIN Members AS b
WHERE Strategies.ID='2'
AND Strategies.AuthorID = a.ID
AND Strategies.UpdateAuthorID = b.ID
Use a LEFT JOIN:
SELECT
s.*,
a.Name AS MemberName,
b.Name AS UpdatedMemberName
FROM Strategies AS s
LEFT JOIN Members AS a ON s.AuthorID = a.ID AND s.ID = 2
LEFT JOIN Members AS b ON s.UpdateAuthorID = b.ID AND s.ID = 2 ;
If you want them in one column use COALESCE:
SELECT
s.*,
COALESCE(a.Name, b.Name) AS MemberName
FROM Strategies AS s
LEFT JOIN Members AS a ON s.AuthorID = a.ID AND s.ID = 2
LEFT JOIN Members AS b ON s.UpdateAuthorID = b.ID AND s.ID = 2
SELECT toD.dom_url AS ToURL,
fromD.dom_url AS FromUrl,
rvw.*
FROM reviews AS rvw
LEFT JOIN domain AS toD
ON toD.Dom_ID = rvw.rev_dom_for
LEFT JOIN domain AS fromD
ON fromD.Dom_ID = rvw.rev_dom_from
if domain is table name