How can I join 3 tables in MySQL? - mysql

I have these 4 tables:
Suppliers(id_sup, name, city)
Companies( id_co, name, city)
Products(id_p, name, city)
Deliveries (id_sup, id_co, id_p)
in one query, I need to get a list of all cities (no duplicates) and for each, show the number of suppliers, companies, and products that can be found in that city.
In oracle SQL I would have used some Full OUTER JOIN. what's the alternative?
This is a suggested solution for joining 2 of the tables:
SELECT city
, COUNT(DISTINCT id_sup) Suppliers
, COUNT(DISTINCT id_co) Companies
FROM ( SELECT COALESCE(s.city,c.city) city
, id_sup
, id_co
FROM Suppliers AS s
LEFT OUTER JOIN Companies AS c ON c.city = s.city
UNION
SELECT COALESCE(s.city,c.city) city
, id_sup
, id_co
FROM Suppliers AS s
RIGHT OUTER JOIN Companies AS c ON c.city = s.city ) AS union_query
GROUP BY city
How to add the final table Products to the mix?

With UNION get all the cities from all 3 tables and LEFT join to the results the 3 tables to finally aggregate:
select t.city,
count(distinct s.id_sup) counter_suppliers,
count(distinct c.id_co) counter_companies,
count(distinct p.id_p) counter_products
from (
select city from suppliers union
select city from companies union
select city from products
) t
left join suppliers s on s.city = t.city
left join companies c on c.city = t.city
left join products p on p.city = t.city
group by t.city
See a simplified demo.

Just use union all and group by:
select city, sum(is_supplier), sum(is_company),
sum(is_product), sum(is_delivery)
from ((select city, 1 as is_suppler, 0 as is_company, 0 as is_product, 0 as is_delivery
from suppliers
) union all
(select city, 0 as is_suppler, 1 as is_company, 0 as is_product, 0 as is_delivery
from companies
) union all
(select city, 0 as is_suppler, 0 as is_company, 1 as is_product, 0 as is_delivery
from products
) union all
(select city, 0 as is_suppler, 0 as is_company, 0 as is_product, 1 as is_delivery
from deliveries
)
) c
group by city;
Or, even more simply in MySQL:
select city, sum(which = 'supplier'), sum(which = 'company'),
sum(which = 'product'), sum(which = 'delivery')
from ((select city, 'suppler' as which from suppliers
) union all
(select city, 'company' as which from companies
) union all
(select city, 'product' as which from products
) union all
(select city, 'delivery' as which from deliveries
)
) c
group by city;

to get all cities, since we don't have a city table as a dimension, we can get the domain from each of the city columns from each of the three tables, and combine them with UNION set operator:
SELECT cs.city
FROM suppliers cs
GROUP BY cs.city
UNION
SELECT cc.city
FROM companies cc
GROUP BY cc.city
UNION
SELECT cp.city
FROM products cp
GROUP BY cp.city
That should get us a list of distinct city values that appear in the three tables.
We could take that set, and do outer join operations to the individual tables. But that has the potential to generate cross product... if there are three suppliers related to a city and four companies related to the same city, we would generate a resultset of twelve rows.
To fix that, we could get a count of DISTINCT primary key values.
Or, we can pre-aggregate the results in inline views, returning a single row per city. That avoids the problem of semi-cartesian products.
Let's reference the query above in an line view in another query. We will alias it ci. (If we had a dimension table city, we could reference that,)
Something like this:
SELECT ci.city
, IFNULL(np.cnt_,0) AS cnt_products
, IFNULL(nc.cnt_,0) AS cnt_companies
, IFNULL(ns.cnt_,0) AS cnt_suppliers
FROM ( /* inline view query */ ) ci
LEFT
JOIN ( SELECT p.city
, COUNT(1) AS cnt_
FROM products p
GROUP BY p.city
) np
ON np.city = ci.city
LEFT
JOIN ( SELECT c.city
, COUNT(1) AS cnt_
FROM companies c
GROUP BY c.city
) nc
ON nc.city = ci.city
LEFT
JOIN ( SELECT s.city
, COUNT(1) AS cnt_
FROM suppliers s
GROUP BY s.city
) ns
ON ns.city = ci.city
ORDER BY ci.city
(In place of /* inline view query */, use the SQL text from the first query, to generate the distinct list of city.)

Related

How do i retrieve data from table using group by having foll0wing condition

List of all countries having more than 2 COVID-19 affected males.
select * from country
where country_id in(select country_id
from(select country_id, count(*)
from person
where Gender="Male"
and virus_id=(select virus_id
from virus
where virus_name="crona_virus"
)
group by country_id
having count(*)>2
)as tbl
);
I do get the results but those are not desired.
IN could be replaced by join and sub queries replaced by join
select country.*
from country
join
(select country_id, count(*)
from person
join virus on person.virus_id = virus.virus_id and virus_name = 'corona_virus'
group by country_id having count(*)>2
)as tbl
on country.country_id = tbl.country_id;

query that select distinct elements

I want to print the name of all companies that have done at least 3 sponsorizations on different cities
ps: kid is primary key of company
This is what I tied so far but this return all companies that has at least 3 sponsorizations but not filter about different cities.
company(kid, name)
sponsorization(kid, city, sum_of_sponsorization)
SELECT c.name, count(c.name)
FROM COMPANY c
INNER JOIN SPONSORIZATION s
ON c.kid = s.kid
GROUP BY
c.name
having count(c.name) > 3
You can try below- with count(distinct s.city)
SELECT c.name
FROM COMPANY c
INNER JOIN SPONSORIZATION s ON c.kid = s.kid
GROUP BY
c.name
having count(distinct s.city) > 3
count distinct city
SELECT c.name
FROM COMPANY c
INNER JOIN SPONSORIZATION s
ON c.kid = s.kid
GROUP BY
c.name
having count(distinct s.city) > 3

SUM, COUNT with LEFT JOIN?

How can i get right sum and count with LEFT JOIN?
Now rows sum from both tables..
Is it possible to do without subquery?
SELECT
t1.Continent, t1.Region,
COUNT( t1.Region ) AS cRegion, t1.LifeExpectancy,
SUM( t1.Population ) AS sPopulation, SUM( t2.CountryCode ) AS cCities
FROM Country AS t1
LEFT JOIN City AS t2 ON t1.Code = t2.CountryCode
GROUP BY t1.Region
ORDER BY t1.Continent ASC
City Table
Country Table
Your query doesn't make any sense. But if you join together the City and Country table, and group by the region, then you can compute the following stats for each region:
number of cities per region
number of countries per region
total population per region
SELECT t1.Region,
COUNT(*) AS cityCount,
COUNT(DISTINCT t1.code) AS countryCount,
SUM(t2.Population) AS regionPop
FROM Country t1
LEFT JOIN City t2
ON t1.Code = t2.CountryCode
GROUP BY t1.Region

MySQL Statement not returning as expected

I have 3 tables:
SUPPLIERS:
id, name, address, suburb, state, phone, email, deleted
CUSTOMERS:
id, name, address, suburb, state, phone, email, deleted
ACCREDITED_SUPPLIERS:
id, supplier_id, customer_id
I want to display all SUPPLIERS and 'tag' those that are already linked in ACCREDITED_SUPPLIERS...
Here is my statement:
SELECT SQL_CALC_FOUND_ROWS s.id, s.name, s.suburb, s.state, s.phone, s.email, s.deleted,
IF( ac.customer_id = '220', 1, 0 ) AS accredited
FROM suppliers s
LEFT OUTER JOIN accredited_suppliers ac ON ac.supplier_id = s.id
WHERE s.deleted='0'
ORDER BY s.name
This statement only returns 10 'tagged' rows
For some reason it is missing 3 rows inexplicably!
SELECT *
FROM `accredited_suppliers`
WHERE `customer_id` = '220'
RETURNS: 13 rows
Is my statement above correct? Am I issuing it correctly?
Don't you just want:
select
s.id AS supplier_id,
IF(a.supplier_id IS NULL, 0, 1) AS accredited
from
SUPPLIERS s
left join
ACCREDITED_SUPPLIERS a
ON
s.id = a.supplier_id AND
a.customer_id = 220;

MySQL Join Query (possible two inner joins)

I currently have the following:
Table Town:
id
name
region
Table Supplier:
id
name
town_id
The below query returns the number of suppliers for each town:
SELECT t.id, t.name, count(s.id) as NumSupplier
FROM Town t
INNER JOIN Suppliers s ON s.town_id = t.id
GROUP BY t.id, t.name
I now wish to introduce another table in to the query, Supplier_vehicles. A supplier can have many vehicles:
Table Supplier_vehicles:
id
supplier_id
vehicle_id
Now, the NumSupplier field needs to return the number of suppliers for each town that have any of the given vehicle_id (IN condition):
The following query will simply bring back the suppliers that have any of the given vehicle_id:
SELECT * FROM Supplier s, Supplier_vehicles v WHERE s.id = v.supplier_id AND v.vehicle_id IN (1, 4, 6)
I need to integrate this in to the first query so that it returns the number of suppliers that have any of the given vehicle_id.
SELECT t.id, t.name, count(s.id) as NumSupplier
FROM Town t
INNER JOIN Suppliers s ON s.town_id = t.id
WHERE s.id IN (SELECT sv.supplier_id
FROM supplier_vehicles sv
WHERE sv.vehicle_id IN (1,4,6))
GROUP BY t.id, t.name
Or you could do an INNER JOIN (as your supplier join is INNER, but this will remove towns with no suppliers with those vehicles) and change the COUNT(s.id) TO COUNT(DISTINCT s.id)
If I remember correctly, you can put your second query inside the LEFT OUTER JOIN condition.
So for example, you can do something like
...
LEFT OUTER JOIN (SELECT * FROM Suppler s, Supplier_vehicles ......) s ON s.town_id=t.id
In that way you are "integrating" or combining the two queries into one. Let me know if this works.
SELECT t.name, count(s.id) as NumSupplier
FROM Town t
LEFT OUTER JOIN Suppliers s ON t.id = s.town_id
LEFT OUTER JOIN Supplier_vehicles v ON s.id = v.supplier_id
WHERE v.vehicle_id IN (1,4,6)
GROUP BY t.name