SQL Query in Linq with HAVING SUM - linq-to-sql

I have a small database example with three tables: Cities, Country and Geo_Languages (Languages spoken in the countries). Now I want to get the most spoken languages of all cities in the world with a population of at least one million people.
Here is the SQL-Query:
SELECT SUM(c.population) AS totalPop, g.name_en
FROM cities c, country cy, geo_languages g
WHERE c.country_code = cy.id AND
cy.id = g.code2l
GROUP BY g.name_en
HAVING SUM(c.population) > 1000000
ORDER BY totalPop DESC;
Here the Linq-Query so far:
Var query =
from c in db.City
join country in db.Country on c.country_code equals country.id
join languages in db.geo_languages on country.id equals
languages.code2l
group languages by languages.name_en
select new{
totalPop = c.Sum (c => c.population)
};
I just don't know how to convert the HAVING SUM and the ORDER BY into Linq.
I'm thankful for any help.

Try that one:
var query =
from c in db.City
join country in db.Country on c.country_code equals country.id
join languages in db.geo_languages on country.id equals
languages.code2l
group c by languages.name_en into g
where g.Sum(x => x.population) > 1000000
select new {
totalPop = g.Sum(x => x.population)
};

Related

How can this SQL query be optimized? (Running on MySQL)

I need help on rewriting an SQL query that takes 26 seconds to run on an MySQL server.
The query is:
select
c.countries_name,
c.country_id,
(SELECT
count(1)
FROM
`fav_country`
WHERE
`country_id`=c.country_id
and device_id='".$device_id."'
) as isFav,
c.image,
c.countries_iso_code,
s.country
from
station s
left join countries c on c.country_id=s.country
where
isactive=:isactive
group by
s.country
I have tried rewriting it with two left/right joins but to no avail.
Basically, we have three tables, countries, fav_country and station, the common field is the country id (countries.country_id, fav_country.countr_id and station.country)
Thanks in advance!
This is the query you want optimized:
select c.countries_name, c.country_id,
(select count(1)
from fav_country fc
where fc.country_id = c.country_id and
fc.device_id = ? -- use a parameter!
) as isFav,
c.image, c.countries_iso_code
from station s left join
countries c
on c.country_id = s.country
where s.isactive = :isactive
group by s.country;
First, avoiding the outer aggregate is very helpful. I would replace it with exists:
select c.countries_name, c.country_id,
(select count(1)
from fav_country fc
where fc.country_id = c.country_id and
fc.device_id = ?
) as isFav,
c.image, c.countries_iso_code
from countries c
where exists (select 1
from station s
where s.country = c.country_id and
s.isactive = :isactive
);
Then for this query, you want indexes on:
station(country, isactive)
fav_country(country_id, device_id).

Group by not getting the expected results in mysql

I have the next query:
SELECT DISTINCT
bt.name, b.id
FROM
ports po,
cities c,
provinces p,
countries co,
states s,
translations t,
element_types et,
languages l,
boat_models bm,
boat_types bt,
boats b
JOIN
boat_prices bprf ON b.id = bprf.boat_id
AND bprf.checkin_date IS NULL
AND bprf.duration_id IS NULL
WHERE
t.element_translation = 'España'
AND et.name = 'Country'
AND s.name = 'confirmed'
AND s.id = b.state_id
AND l.locale = 'es'
AND t.language_id = l.id
AND t.element_type_id = et.id
AND t.element_id = p.country_id
AND c.province_id = p.id
AND po.city_id = c.id
AND b.port_id = po.id
AND bm.id = b.boat_model_id
AND bt.id = bm.boat_type_id
That is working perfectly and returning 9 rows:
'BOAT_TYPE_CATAMARAN','13707'
'BOAT_TYPE_SAILBOAT','13700'
'BOAT_TYPE_SAILBOAT','13701'
'BOAT_TYPE_SAILBOAT','13702'
'BOAT_TYPE_SAILBOAT','13703'
'BOAT_TYPE_SAILBOAT','13704'
'BOAT_TYPE_SAILBOAT','13705'
'BOAT_TYPE_SAILBOAT','13706'
'BOAT_TYPE_SAILBOAT','13708'
I want to group the results by boat type and get the number of boats per type.
However, when I do:
SELECT DISTINCT
bt.name, COUNT(b.id) AS num_boats
FROM
ports po,
cities c,
provinces p,
countries co,
states s,
translations t,
element_types et,
languages l,
boat_models bm,
boat_types bt,
boats b
JOIN
boat_prices bprf ON b.id = bprf.boat_id
AND bprf.checkin_date IS NULL
AND bprf.duration_id IS NULL
WHERE
t.element_translation = 'España'
AND et.name = 'Country'
AND s.name = 'confirmed'
AND s.id = b.state_id
AND l.locale = 'es'
AND t.language_id = l.id
AND t.element_type_id = et.id
AND t.element_id = p.country_id
AND c.province_id = p.id
AND po.city_id = c.id
AND b.port_id = po.id
AND bm.id = b.boat_model_id
AND bt.id = bm.boat_type_id
GROUP BY bt.name
ORDER BY bt.name
I´m getting:
'BOAT_TYPE_CATAMARAN','241'
'BOAT_TYPE_SAILBOAT','1928'
but according to the first query, I´m expecting
'BOAT_TYPE_CATAMARAN','1'
'BOAT_TYPE_SAILBOAT','8'
What am I missing?
I suspect that you want:
SELECT bt.name, COUNT(DISTINCT b.id) AS num_boats
FROM ...
WHERE ...
GROUP BY bt.name
ORDER BY bt.name
That is: move the DISTINCT within the COUNT() rather than directly in the SELECT.
Generally speaking, DISTINCT and GROUP BY do not go along well together; DISTINCT is already aggregation in essence, so mixing both is usually not relevant.
Note that your syntax uses old-school, implicit joins (with a comma in the FROM clause): you should be using standard joins (with the ON keyword), whose syntax has been state-of-the-art for decades.
You are doing a distinct in your first query so you are 'hiding' a lot if rows that gets doubled because of your join.

Counting average from two queries

I'm trying get the average from two select queries. In the first select i'm counting all "votes" per district, now i want to devide it by total sum of votes in voivodeship(It can have more than one district)
select void.name, d.name, t.name, COUNT(v.idvotes) as "Percent of votes"
from voivodeship void, politicialteam t, votes v, candidates c, person p, district d
where c.idcandidates = v.idcandidates
and p.idperson = c.idperson
and c.idpoliticialteam = t.idpoliticialteam
and void.idvoivodeship = d.idvoivodeship
and c.iddistrict = d.iddistrict
GROUP by d.name ORDER by void.name ASC
SELECT Count(vo.idvotes)
from votes vo, candidates c, district d, voivodeship v
where d.idvoivodeship = v.idvoivodeship
and d.iddistrict = c.iddistrict
and vo.idcandidates = c.idcandidates
GROUP by v.name
Total for "dolnośląskie": 119987
In my example i want merge this two queries to get result 40038/119987, 40078/119987 etc..
You can achieve this result in two different way, depending on your DBMS.
If your DBMS supports Extended SQL queries, you should try to get a partition on void.name and aggregate the result in order to compute your percentage:
SELECT void.name,
d.name,
t.name,
COUNT(v.idvotes) as "Percent of votes",
COUNT(v.idvotes)/SUM(COUNT(v.idvoted))*100 OVER (PARTITION BY void.name) as "Votes percentage"
FROM voivodeship void, politicialteam t, votes v, candidates c, person p, district d
where c.idcandidates = v.idcandidates and
p.idperson = c.idperson and
c.idpoliticialteam = t.idpoliticialteam and
void.idvoivodeship = d.idvoivodeship and
c.iddistrict = d.iddistrict
GROUP BY d.name, void.name
ORDER BY void.name ASC
If your DBMS does not support Extended SQL, you can achieve the same result nesting the two queries:
SELECT void.name,
d.name,
t.name,
COUNT(v.idvotes) as "Percent of votes",
COUNT(v.idvotes)/(
SELECT Count(vo.idvotes)
FROM votes vo1, candidates c1, district d1, voivodeship v1
WHERE d1.idvoivodeship = v1.idvoivodeship and
d1.iddistrict = c1.iddistrict and
vo1.idcandidates = c1.idcandidates and
d1.name = d.name
GROUP BY v.name
)*100 AS "Percentage of votes"
FROM voivodeship void, politicialteam t, votes v, candidates c, person p, district d
where c.idcandidates = v.idcandidates and
p.idperson = c.idperson and
c.idpoliticialteam = t.idpoliticialteam and
void.idvoivodeship = d.idvoivodeship and
c.iddistrict = d.iddistrict
GROUP BY d.name, void.name
ORDER BY void.name ASC
N.B. In the last solution you can merge the queries adding another JOIN condition on the nested query such as
d1.name = d.name

Show names from two values

I am trying to get a SQL code but can't really figure out how to do it so I will explain what I want.
I have 4 tables called Person, Customer, Adres and Store. Now I have to show each customer NAMES which lives in the same city as where there is a Store. So First I figured out which persons are customers by:
SELECT person_name
FROM person
WHERE person_id IN
(SELECT Person_Person_Id
FROM customer);
Which stores are in which city:
SELECT Store_name, adres_city
FROM store s, adres a
WHERE s.Adres_Adres_Id = a.adres_id;
Note that person_person_id is the same as person_id just as a fk.
I am stuck at this code and don''t know how to go further from here. My column name of table adres = adres_city.
Okay, if I realised what do you want, try to do this:
select --distinct
b.Adres_City,
a.person_id
from
dbo.Person a
join dbo.Adres b on a.adres_adres_id = b.Adres_Id
join dbo.Customer c on a.person_id = c.Person_Person_Id
join dbo.Store d on b.Adres_Id = d.Adres_Adres_Id
If you are not sure, that all your keys in tables are uniq, uncomment --distinct in the first string.
Or, if you are want to know statistics among your cities, do this:
select
b.Adres_City,
count(distinct a.person_id) as cnt
from
dbo.Person a
join dbo.Adres b on a.adres_adres_id = b.Adres_Id
join dbo.Customer c on a.person_id = c.Person_Person_Id
join dbo.Store d on b.Adres_Id = d.Adres_Adres_Id
group by b.Adres_City
Please let me know, if it will help you.
Update1:
select --distinct
b.Adres_City,
a.person_id
from
dbo.Person a
join dbo.Adres b on a.adres_adres_id = b.Adres_Id
join dbo.Customer c on a.person_id = c.Person_Person_Id
where
b.Adres_City in (
select y.Adres_City
from dbo.Store x join dbo.Adres y on y.Adres_Id = x.Adres_Adres_Id
)

Keeps saying error 105

I'm trying to write q query for my sql sever for a database where i retrieve the HotelID's and names of all Hotels in Melbourne that have King size beds but it comes up with HotelID in field list is ambiguous i dont know how to solve this? this is my query
SELECT City, BedTypeDesc, HotelName, HotelID
FROM BedTypes, Hotels, Cities, Rooms
WHERE Hotels.CityID = Cities.CityID AND Hotels.HotelID = Rooms.HotelID AND Rooms.BedTypeID = BedTypes.BedTypeID AND BedTypeDesc = 'King Size' AND City = 'Melbourne'
You should use table aliases an proper join syntax:
SELECT c.City, bt.BedTypeDesc, h.HotelName, h.HotelID
FROM Hotels h JOIN
Cities c
ON h.CityID = c.CityID JOIN
Rooms r
ON h.HotelID = r.HotelID JOIN
BedTypes bt
ON r.BedTypeID = bt.BedTypeID
WHERE bt.TypeDesc = 'King Size' AND c.City = 'Melbourne' ;