SUM, COUNT with LEFT JOIN? - mysql

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

Related

max(count ) from 2 tables mysql

Finding the city in which the most orders were sent leads to the assignment of the city and the number of orders (the named amount column). I have 2 tables the named Customers and Orders
SELECT Customers.City,count( Orders.OrderID) as amount
FROM voodoo.Customers
inner join voodoo.Orders on Customers.CustomerID=Orders.CustomerID
group by Customers.City
having amount >= all(select count(Orders.OrderID)
from voodoo.Customers
inner join voodoo.Orders on Customers.CustomerID=Orders.CustomerID
group by Customers.City);
tables
You don't need a subquery as you can just order by amount (descending) and limit the result to 1:
SELECT Customers.City, count(Orders.OrderID) as amount
FROM voodoo.Customers INNER JOIN voodoo.Orders
ON Customers.CustomerID=Orders.CustomerID
GROUP BY Orders.OrderID
ORDER BY amount DESC
LIMIT 1;
EDIT: as Thorsten Kettner pointed out, I made a copy & paste error; the correct version would GROUP BY Customers.City.
You are looking for the order count per city, not per order. So, don't group by order, but by city. For the ranking of the cities you can use RANK or DENSE_RANK.
SELECT city, amount
FROM
(
SELECT
c.city,
COUNT(o.orderid) AS amount,
RANK() OVER (ORDER BY COUNT(o.orderid) DESC) AS rnk
FROM voodoo.customers c
INNER JOIN voodoo.orders o ON o.customerid = c.customerid
group by c.city
) counted_and_ranked
WHERE rnk = 1;

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;

How can I join 3 tables in 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.)

MySQL Ordering by SubQuery

I'm trying to pull a list of customers who place the most orders. I can't seem to figure out how to keep the list ordered by the sub query. Here's my query:
SELECT
c.*,
state.abbreviation AS state,
country.abbreviation AS country
FROM main_customers AS c
LEFT JOIN dict_stateProvince AS state ON c.state = state.id
LEFT JOIN dict_country AS country ON c.country = country.id
WHERE c.id IN (SELECT customerId
FROM main_orders
GROUP BY customerId
ORDER BY COUNT(*) DESC)
LIMIT 50;
How do I keep the order of the main query the same as the subquery?
Your subquery doesn't have a real order, because IN ignores the ordering. But the intention is clear. So, use a join:
SELECT c.*,
state.abbreviation AS state,
country.abbreviation AS country
FROM main_customers AS c JOIN
(SELECT customerId, COUNT(*) as cnt
FROM main_orders
GROUP BY customerId
) mo
ON mo.customerId = c.id LEFT JOIN
dict_stateProvince AS state
ON c.state = state.id LEFT JOIN
dict_country AS country
ON c.country = country.id
ORDER BY mo.cnt DESC;

SQL for getting top user based on rating and using result to get additional data

I'm trying to come up with an SQL which gets every
country's name,
code,
number of games,
TOP player's name and
his id
based on the SUM(rating) in the games table.
I'm having trouble with getting the name of the top player based on the rating.
SQLFiddle Demo
SELECT x.Country AS CountryName,
x.Code,
a.totalCount as NumberOfGames,
y.Name AS PlayersName,
y.ID AS PlayersID,
a.totalRating
FROM (
SELECT player_ID, Country, COUNT(*) totalCount, SUM(Rating) totalRating
FROM Games
GROUP BY player_ID, Country
) a
INNER JOIN
(
SELECT Country, Max(totaLRating) maxRating
FROM
(
SELECT player_ID, Country, SUM(Rating) totalRating
FROM Games
GROUP BY player_ID, Country
) s
GROUP BY Country
) b ON a.Country = b.Country AND
a.totalRating = b.maxRating
INNER JOIN Country x
ON a.Country = x.ID
INNER JOIN Players y
ON a.player_ID = y.ID
SQLFiddle Demo
select top 1 * from games inner join players on games.player_id=players.id inner join country on games.country=country.id order by rating desc
Try this query
select
c.id as country_id,
c.name as Country,
c.code as CCode,
g.T_Games,
p.id as Player_id,
p.name as Player
from country as c
left join (select country , count(country) as T_Games from games group by country) as g on g.country = c.id
left join (select id , country , player_id , max(rating) from games group by country) as gl on gl.country = c.id
left join (select id , name from player) as p on p.id = gl.player_id
Here is the demo on sql fiddle
http://sqlfiddle.com/#!2/f74a7/1