Mysql left join, sum, and group_by - mysql

i've 4 tables. region, land, house, and goods.
land have one-to-one rels. with region.
land have one-to-many rels. with house.
house have one-to-many rels. with goods.
sqlfiddle: http://sqlfiddle.com/#!9/5eaec
current query:
SELECT
Sum(land.wide) AS land_wide,
Sum(house.price) AS house_price,
Sum(goods.amount) AS goods_amount,
Sum(goods.price) AS goods_price,
region.region_name
FROM
land
LEFT JOIN house ON house.land_id = land.id
LEFT JOIN goods ON goods.house_id = house.id
LEFT JOIN region ON land.region_id = region.id
GROUP BY
region.region_name
ORDER BY
region.id ASC
but not works as expected.
desired output:
+-----------+-------------+-------------+--------------+---------+
| land_wide | house_price | goods_price | goods_amount | region |
+-----------+-------------+-------------+--------------+---------+
| 510 | 57910 | 1900 | 56 | Tokyo |
| | | | | Osaka |
| | | | | Nagoya |
| | | | | Sapporo |
+-----------+-------------+-------------+--------------+---------+
Would someone kindly offer me a solution which would help? I am pretty sure it could be done in SQL?

SELECT
land_wides.land_wide,
house_prices.house_price,
goods_amounts_prices.goods_price,
goods_amounts_prices.goods_amount,
region.region_name
FROM region
LEFT JOIN (SELECT
Sum(land.wide) AS land_wide,
region.id AS region_id
FROM region
LEFT JOIN land ON land.region_id = region.id
GROUP BY region.id) land_wides ON region.id = land_wides.region_id
LEFT JOIN (SELECT
Sum(house.price) AS house_price,
region.id AS region_id
FROM region
LEFT JOIN land ON land.region_id = region.id
LEFT JOIN house ON house.land_id = land.id
GROUP BY region.id) house_prices ON region.id = house_prices.region_id
LEFT JOIN (SELECT
Sum(goods.amount) AS goods_amount,
Sum(goods.price) AS goods_price,
region.id AS region_id
FROM region
LEFT JOIN land ON land.region_id = region.id
LEFT JOIN house ON house.land_id = land.id
LEFT JOIN goods ON goods.house_id = house.id
GROUP BY region.id) goods_amounts_prices on goods_amounts_prices.region_id = region.id
ORDER BY region.id

Left join should be inner join. You want to have grouping on matching rows. Not unmatched rows, hence grouping on sum.

Related

MySQL get sum in nested left joins

I've a food listing system. It has five tables.
REGIONS
BANNERS
CUISINE
RESTAURANTS
RESTAURANT_SPONSORED
BANNERS, CUISINE and RESTAURANT_SPONSORED table records the revenue of advertising.
I want to generate this table.
name | banner_revenue | cuisine_revenue | restaurant_promotions
------------------------------------------------------------------
NY | 10,000 | 4,800 | 12,000
Paris | NULL | 8,000 | 8,000
London | NULL | NULL | 2,000
This query will output,
SELECT r.name,
sb.fee,
sc.fee
FROM REGIONS r
LEFT JOIN (SELECT sum(b.fee) fee,
b.region_id
FROM BANNERS b
GROUP BY b.region_id) sb
ON sb.region_id = r.id
LEFT JOIN (SELECT sum(c.fee) fee,
c.region_id
FROM CUISINE c
GROUP BY c.region_id) sc
ON sc.region_id = r.id;
name | banner_revenue | cuisine_revenue |
--------------------------------------------
NY | 10,000 | 4,800 |
Paris | NULL | 8,000 |
London | NULL | NULL |
But how do I get restaurant_promotions part? Which is needed a nested left join.
DB Fiddle demo
modify your query to :
SELECT r.name,
sb.fee,
sc.fee,
sr.fee
FROM REGIONS r
LEFT JOIN (SELECT sum(b.fee) fee,
b.region_id
FROM BANNERS b
GROUP BY b.region_id) sb
ON sb.region_id = r.id
LEFT JOIN (SELECT sum(c.fee) fee,
c.region_id
FROM CUISINE c
GROUP BY c.region_id) sc
ON sc.region_id = r.id
LEFT JOIN(SELECT sum(RESTAURANT_SPONSORED.fee) fee,
R.region_id
FROM RESTAURANTS R
LEFT JOIN RESTAURANT_SPONSORED ON(RESTAURANT_SPONSORED.restaurant_id = R.id)
GROUP BY R.region_id) sr
ON sr.region_id= r.id
this should work

MySQL join query on three tables which connected to each other

I have three tables like this:
Animal
| id | cat_id | horse_id | dog_id |
|:--:|:------:|:--------:|--------|
| 1 | 15 | 16 | 17 |
Cat
| id | lang_id |
|:--:|:-------:|
| 15 | 3716 |
Horse
| id | lang_id |
|:--:|:-------:|
| 16 | 3717 |
Dog
| id | lang_id |
|:--:|:-------:|
| 17 | 3718 |
Language
| id | en |
|:----:|:--------------:|
| 3716 | BRAVE LEGEND |
| 3717 | N Rawiller |
| 3718 | DRAGON GENERAL |
I want to get all the animals en name from Language table through each animal's table lang_id. It would be like by using Animal: cat_id -> Cat: lang_id -> Language: en. The final results would be like:
| animal_id | cat_name | horse_name | dog_name |
|:---------:|:------------:|:----------:|:--------------:|
| 1 | BRAVE LEGEND | N Rawiller | DRAGON GENERAL |
I am trying to use this:
select animal.id, lang.* from animal
left join cat on animal.cat_id = cat.id
left join horse on animal.horse_id = horse.id
left join dog on animal.dog_id = dog.id
left join lang on cat.lang_id = lang.id or (horse.lang_id = lang.id) or (dog.lang_id = lang.id)
where animal.id = 1
But I can't get cat_name, dog_name, horse_name because it's all coming from the same Language table.
Try below query:
You need to JOIN lang table multiple times, using one JOIN with multiple OR will not give you desired result,
SELECT animal.id, lang.en as cat_name,l1.en as horse_name,l2.en as dog_name
FROM animal
LEFT JOIN cat ON animal.cat_id = cat.id
LEFT JOIN horse ON animal.horse_id = horse.id
LEFT JOIN dog ON animal.dog_id = dog.id
LEFT JOIN lang ON cat.lang_id = lang.id
LEFT JOIN lang l1 ON horse.lang_id = l1.id
LEFT JOIN lang l2 ON dog.lang_id = l2.id
WHERE animal.id = 1
Try this:
select animal.id, lang1.cat_name, lang2.horse_name, lang3.dog_name
from animal
left join cat on animal.cat_id = cat.id
left join horse on animal.horse_id = horse.id
left join dog on animal.dog_id = dog.id
left join lang AS lang1 on cat.lang_id = lang1.id
left join lang AS lang2 ON horse.lang_id = lang2.id
left join lang AS lang3 ON (dog.lang_id = lang3.id)
where animal.id = 1
Try this:
SELECT a.id, lang1.en as cat_name,lang2.en as horse_name,lang3.en as dog_name
FROM `animal` a
LEFT JOIN cat c ON c.id = a.cat_id
LEFT JOIN LANGUAGE l on l.id=c.lang_id
LEFT JOIN dog d ON d.id = a.dog_id
LEFT JOIN horse h ON h.id = a.horse_id
LEFT JOIN language lang1 ON c.lang_id=lang1.id
LEFT JOIN language lang2 ON h.lang_id=lang2.id
LEFT JOIN language lang3 ON d.lang_id=lang3.id

sql query combine two queries into one with empty rows

This is my sql table structure:
Table1: details
|--id--|--id_user--|--price--|
| 1 | 1 | 10 |
| 2 | 2 | 15 |
| 3 | 1 | 25 |
| 4 | 3 | 30 |
| 5 | 3 | 7 |
------------------------------
Table2: users
|--id--|--id_country--|
| 1 | 1 |
| 2 | 2 |
| 3 | 0 |
-----------------------
Table3: country
|--id--|--country--|
| 1 | France |
| 2 | Italy |
--------------------
What I need is to get the SUM of price by country:
SELECT c.country, SUM(d.price) AS price
FROM details d
INNER JOIN users u ON u.id = d.id_user
INNER JOIN country c ON c.id = u.id_country
GROUP BY c.country
ORDER BY c.country
I get this:
|--country--|--price--|
| France | 35 |
| Italy | 15 |
-----------------------
BUT I'd need to get this:
|--country--|--price--|
| France | 35 |
| Italy | 15 |
| Undefined | 37 |
-----------------------
where undefined would be if id_country=0. (I can't add to country table the id=0 or id=undefined, it will messed up other things). Right now I'm achieving this by two separate queries, the second one is:
SELECT SUM(d.price) as price
FROM details d
INNER JOIN users u ON u.id = d.id_user AND u.id_country=0
GROUP BY u.id_country
I'm thinking if... is it possible to do this in one query?
You need to use left join in this case:
SELECT c.country, SUM(d.price) AS price
FROM details d
LEFT JOIN users u ON u.id = d.id_user
LEFT JOIN country c ON c.id = u.id_country
GROUP BY c.country
ORDER BY c.country
If you use INNER JOIN, you will only get results that exists in both tables.
To replace NULL with Undefined use:
SELECT IFNULL(c.country,'Undefined') AS Country, SUM(d.price) AS price
FROM details d
LEFT JOIN users u ON u.id = d.id_user
LEFT JOIN country c ON c.id = u.id_country
GROUP BY c.country
ORDER BY c.country
One way to sort to get Undefined last is to add a Sortfield
SELECT A.Country,A.Price FROM (
SELECT IFNULL(c.country,'Undefined') AS Country, SUM(d.price) AS price, IFNULL(c.Country,'ZZZZZZZZ') AS Sort
FROM details d
LEFT JOIN users u ON u.id = d.id_user
LEFT JOIN country c ON c.id = u.id_country
GROUP BY c.country
) A
ORDER BY A.Sort
Edit: ORDER BY suggested in comments
SELECT IFNULL(c.country,'Undefined') AS Country, SUM(d.price) AS price
FROM details d
LEFT JOIN users u ON u.id = d.id_user
LEFT JOIN country c ON c.id = u.id_country
GROUP BY c.country
ORDER BY c.country IS NULL, c.country
Try below query.
SELECT
CASE
WHEN c.country is NULL THEN 'Undefined'
ELSE c.country
END as country
, SUM(d.price) AS price
FROM users u
left JOIN details d ON u.id = d.id_user
left JOIN country c ON c.id = u.id_country
GROUP BY c.country
ORDER BY c.country
For Demo :
SqlfiddlE Demo :
Please let us know if you have any que.

count equal fields of 2 Tables and Inner join with 3rd

I have 3 tables
Table cases: docket is pk
| docket | dt_file |
-----------------------
|AA-0322 | 01-22-2015 |
|AA-0431 | 03-21-2014 |
Table parties:
| id | docket | name |
----------------------------
| 1 | AA-0322 | Bob |
| 2 | AA-0322 | John |
Table motions:
| id | docket | motion |
-----------------------------
| 1 | AA-0322 | Summons|
| 2 | AA-0322 | Guilty |
I want to count the number of fields in parties and motion that have the same docket and then make a table with table.cases with the dt_file
example:
| docket | party_count | motion_count| dt_file |
-----------------------------------------------
AA-0322| 2 | 2 | 02-22-2015|
I also want to filter by dt_file, so adding a WHERE statement ex:
WHERE YEAR(dt_file) = '2015'
So far i've came up with this, but I havn't had success joining table.cases with dt_file correctly.
SELECT p.docket, p.party_count, m.motion_count
FROM
(SELECT docket, COUNT(docket) AS party_count
FROM parties
GROUP BY docket) AS p
INNER JOIN
(SELECT docket, COUNT(docket) AS motion_count
FROM motions
GROUP BY docket) AS m
ON p.docket = m.docket
Your query seems correct. You just need to add cases to the from clause:
SELECT c.docket, p.party_count, m.motion_count, c.dt_file
FROM cases c JOIN
(SELECT docket, COUNT(docket) AS party_count
FROM parties
GROUP BY docket
) p
ON c.docket = p.docket INNER JOIN
(SELECT docket, COUNT(docket) AS motion_count
FROM motions
GROUP BY docket
) m
ON c.docket = m.docket;
If you want all dockets, even those where there are no motions or parties, then use LEFT JOIN.
Let this be another example.
Select
p.docket,
COUNT(p.docket) As party_count,
COUNT(m.docket) As motion_count,
p.dt_file
From
cases As c
Inner Join parties As p
On c.docket = p.docket
Inner Join motions As m
On c.docket = m.docket
Group By
p.docket,
p.dt_file
Try this:
SELECT p.docket, p.party_count, m.motion_count, c.dt_file
FROM
(SELECT docket, COUNT(docket) AS party_count
FROM parties
GROUP BY docket) AS p
INNER JOIN
(SELECT docket, COUNT(docket) AS motion_count
FROM motions
GROUP BY docket) AS m
ON p.docket = m.docket
INNER JOIN cases c
ON p.docket = c.docket
WHERE YEAR(c.dt_file) = '2015'

How I use mysql count with select query?

I have a mysql select query like this:
select r.restaurant_id, r.restaurant_name, r.city_id, c.name
from restaurants r
inner join cities c on c.id = r.city_id;
This is the result of above query:
+---------------+----------------------+---------+-------------+
| restaurant_id | restaurant_name | city_id | name |
+---------------+----------------------+---------+-------------+
| 7 | Somasiri Bake House | 5 | Mumbai |
| 8 | Indian Bake House | 7 | Chennai |
| 9 | KFC Rest | 5 | Mumbai |
| 10 | Indian t | 5 | Mumbai |
+---------------+----------------------+---------+-------------+
Now I want to display all the available cities with the number of restaurants existing to one city.
Eg: Mumbai (3), Chennai(1) and so on
I tried it like below with mysql COUN(), but it doesn't work for me.
SELECT c.name, count(r.city_id) AS count
FROM cities c
INNER JOIN restaurants r ON c.id = r.city_id;
Can anybody tell me what is the wrong with this?
Hope somebody may help me out.
Thank you.
SELECT c.name, COALESCE(count(r.city_id), 0) AS count
FROM cities c
LEFT JOIN restaurants r ON c.id = r.city_id
GROUP BY c.id
Use a simple group by if you don't want restaurant data:
select c.name, count(r.city_id) as available
from cities c
left join restaurants r on c.id = r.city_id
group by r.city_id
See SQLFiddle.
Or, if you want restaurant data too, select from cities first, then left join to other tables so cities without restaurants still get returned. Add a left join to a subquery that calculates each city's frequency:
select
r.restaurant_id,
r.restaurant_name,
c.id,
c.name,
coalesce(available, 0) available
from cities c
left join restaurants r on c.id = r.city_id
left join (select city_id, count(*) available from restaurants group by 1) a
on a.city_id = r.city_id
See SQLFiddle.
That's called a grouping or aggregate query, you need to tell it how to group your elements.
Just add
GROUP BY r.restaurant_id, r.restaurant_name, r.city_id, c.name
at the end, before your final semi-colon.