Find total count and average based of values from another table - mysql

In Mysql:
I have customer name (primary key), cities and an amount in table:
Table Cities:
customer location amount
Cust1 New York, USA 200
Cust2 New York, USA 300
Cust3 Chicago, USA 100
Cust4 Paris, France 400
Cust5 Nice, France 500
Cust6 Milan, Italy 600
Cust7 Mumbai, India 0
The format of location name in this table is:
<city>, <country>
Same as:
<city><comma><space><country>
Table Country (Primary key):
Name
USA
France
Italy
India
Thailand
I want to get how many cities each country has, and the average amount of each country. Like:
Country Count Average
USA 3 200 // (200 + 300 + 100) / 3
France 2 450 // (400 + 500) / 2
Italy 1 600 // (600) / 1
India 1 0 // (0) / 1
Thailand 0 0 // 0
So, my query is:
SELECT t1.name Country, count(distinct t2.location) Count
FROM Country t1 LEFT JOIN Cities t2
ON t2.location LIKE concat('%, ', t1.name)
GROUP BY t1.name ORDER BY Count DESC
But it does not give Average data, it only gives Country name and Count

Here is one way to do it:
select co.name, count(*) cnt, coalesce(avg(amount), 0) avg
from countries co
left join cities ci
on ci.location like concat('%, ', co.name)
group by co.name
order by co.name
Note that the way you store your data is inefficient. You should:
separate the city name from the country in two different columns
have a primary key in the countries table, and reference it in the cities table
For your dataset, this would be:
Countries
id | name
-- | ---------
1 | USA
2 | France
3 | Italy
4 | India
5 | Thailand
Cities
id | customer | location | country_id | amount
-- | -------- | -------- | ---------- | ------
1 | Cust1 | New York | 1 | 200
2 | Cust2 | New York | 1 | 300
3 | Cust3 | Chicago | 1 | 100
4 | Cust4 | Paris | 2 | 400
5 | Cust5 | Nice | 2 | 500
6 | Cust6 | Milan | 3 | 600
7 | Cust7 | Mumbai | 4 | 0

Related

Create a new column from existing columns

I want to create a new column from this example table but with one more condition that so far I couldn't figure out, I want to create an average holdings column that's specific to each city.
Name | City | Holdings
Tom Jones | London | 42
Rick James| Paris | 83
Mike Tim | NY | 83
Milo James| London | 83
So in this example table London has more than one instance and accordingly it will have a unique value of '62.5' indicating an average of holdings that's specific to the value in the city column.
Name | City | Holdings | City Avg. Holdings
Tom Jones | London | 42 | 62.5
Rick James| Paris | 36 | 36
Mike Tim | NY | 70 | 70
Milo James| London | 83 | 62.5
In MySQL 8.0, this is straight-forward with window functions:
select t.*, avg(holdings) over(partition by city) avg_city_holdings
from mytable t
In earlier versions, you can join:
select t.*, a.avg_city_holdings
from mytable t
left join (select city, avg(holdings) avg_city_holdings from mytable group by city) a
on a.city = t.city

Selecting lowest integer value (non unique) for each table entry that shares the same column value [duplicate]

This question already has answers here:
SQL select only rows with max value on a column [duplicate]
(27 answers)
Closed 3 years ago.
I have a single database table 'Accomodation' that lists information of hotel/B&B suites with the city they are located in, the price and an ID for each suite that functions as the primary key.
It looks similar to this:
id | city | Price
ams001 | Amsterdam | 160
ams011 | Amsterdam | 120
par004 | Paris | 90
par006 | Paris | 120
rom005 | Rome | 130
rom015 | Rome | 130
I want to list all information of the cheapest accomodation for each city, however if two records both share the same lowest price I want to display both of these.
The result should look something like this:
ams011 | Amsterdam | 120
par004 | Paris | 90
rom005 | Rome | 130
rom015 | Rome | 130
I have tried using
SELECT * FROM accomodation
WHERE price IN (SELECT MIN(price) FROM accomodation GROUP BY city);
However this will produce a table like this
ams011 | Amsterdam | 120
par004 | Paris | 90
par006 | Paris | 120
rom005 | Rome | 130
rom015 | Rome | 130
Since the 120 price is the cheapest for Amsterdam it will show up at Paris too.
If I add a group by statement at the end, outside of the subquery like this:
SELECT * FROM accomodation
WHERE price IN (SELECT MIN(price) FROM accomodation GROUP BY city)
GROUP BY city;
It will fail to display lowest values that are identical and I'm left with a table like this:
ams011 | Amsterdam | 120
par004 | Paris | 90
rom015 | Rome | 130
First GROUP BY city to get the min price for each city and then join to the table:
SELECT a.*
FROM accomodation a INNER JOIN (
SELECT city, MIN(price) minprice
FROM accomodation
GROUP BY city
) g ON g.city = a.city AND g.minprice = a.price

MYSQL: Select row based on ranking by joining tables

I have three tables as given:
country
Id | code | name
-------------------------
1 | DE | Germany
2 | IT | Italy
3 | ES | Spain
4 | FR | France
currency
Id | code | name
-------------------------------
1 | EUR | Euro
2 | USD | US Dollors
3 | CAD | Canadian Dollors
country_currency
country_id | currency_id | ranking
-------------------------------------------
1 | 1 | 5
1 | 2 | 10
1 | 3 | 15
2 | 1 | 5
3 | 1 | 10
4 | 2 | 5
4 | 3 | 10
As you see in third table, country_id => 1 has three assigned currencies with different ranking. In other words, Germany has three assigned currencies (EUR and USD and CAD). So, EUR should be display with Germany because it has 5 ranking which is minimum.
For Italy and Spain , only currency_id => 1 is assigned (EUR). So, EUR should be displayed for Italy and Spain.
For France, currency_id => 2 and currency_id => 3 (USD and CAD) but USD has minimum ranking with France row. So, USD should be displayed with France.
Expected Result
country | currency
---------------------------
Germany | EUR
Italy | EUR
Spain | EUR
France | USD
My query
select country.name, currency.code from country_currency
inner join country on country.id = currency_country.country_id
inner join currency on currency.id = currency_country.currency_id
order by ranking asc
group by country_id
It doesn't work at all. Any one can help me to fix this query?
SQLFIDDLE
You can use the following query:
SELECT name AS country,
(SELECT c3.code
FROM country_currency AS c2
INNER JOIN currency AS c3 ON c3.id = c2.currency_id
WHERE c1.id = c2.country_id
ORDER BY ranking LIMIT 1) AS currency
FROM country AS c1;
The above query makes use of a single correlated sub-query in order to get the code value of currency having the minimum ranking per country.
Note: If more than one currencies share the same minimum ranking for a specific country, then one of them is arbitrarily chosen.
Demo here
http://sqlfiddle.com/#!9/2a099/7
SELECT c.name, curr.name
FROM country c
LEFT JOIN country_currency cc
ON cc.country_id = c.id
LEFT JOIN country_currency cc_min
ON cc_min.country_id = cc.country_id
AND cc.ranking > cc_min.ranking
LEFT JOIN currency curr
ON curr.id = cc.currency_id
WHERE cc_min.ranking IS NULL;

MySQL Where Clause - get two cities where ID of 1. row < ID of 2. row

I have two tables:
1) table with travels
id | title
------------------------
1 | travel1
2 | travel2
3 | travel3
2) table with cities
id | city | travel_ID
------------------------
1 | London | 1
2 | York | 1
3 | Newcastle | 1
4 | London | 2
5 | Newcastle | 2
6 | Newcastle | 3
7 | York | 3
id of the cities means also order.
so the question is: How can I get travels if cities (from A to B) are declared. (e.g. from York to Newcastle should get travel1, from London to Newcastle - travel1 and travel2)
If I understand correctly, you want travel ids where the id of the first city is less than the id of the second.
If so, then this may be what you are looking for:
select c1.travelid
from cities c1 join
cities c2
on c1.city = $CITY1 and
c2.city = $CITY2 and
c1.travelid = c2.travelid and
c1.id < c2.id;
If you want the name, you can just join that in:
select t.*
from travels t join
cities c1
on c1.travelid = t.travelid join
cities c2
on c1.city = $CITY1 and
c2.city = $CITY2 and
c1.travelid = c2.travelid and
c1.id < c2.id;

mysql - total count records in parent category

I have following table structure and data in MySQL
TABLE NAME : categories
CatID CatName ParentCatID
-------------------------------
1 Shirts NULL
2 Short Sleev 1
3 Long Sleev 1
4 Collarless 2
5 Collar 2
6 Collarless 3
7 Collar 3
8 Square Cut 4
9 Round Cut 4
10 Square Cut 6
11 Round Cut 6
table name : companies
-------------------------------------------------
companyid | company name | country | categoryid
-------------------------------------------------
1 | Unitile ltd. | India | 5
2 | abc ltd. | India | 2
3 | infocom ltd. | India | 1
4 | tata ltd. | India | 5
5 | agro india | India | 1
I have 2 level of categories like : Shirts > Long Sleev
I want total records count under parent category like Shirts
I don't understand what the companies table has to do with the problem. Something like this may do what you may be trying to achieive
SELECT
C.CatID, COUNT(DISTINCT (IFNULL(PC.CatID, 0))) AS parentcategories
FROM categories C
LEFT JOIN categories PC ON (C.ParentCatID = PC.CatID)
GROUP BY C.CatID
;