not a single-group group function with MAX in select - sql

Select sg_gameno, Max(sg_Year), sg_end, sg_hostcity, country_olympic_name
from Summergames s, Country co
where s.country_isocode = co.country_isocode
Don't know whats wrong with this. I want to get the lastest year. Should i use MAX or something else.

If you want to aggregate one column (sg_year) and to not aggregate others, you need a GROUP BY clause.
Select sg_gameno, Max(sg_Year), sg_end, sg_hostcity, country_olympic_name
from Summergames s,
Country co
where s.country_isocode = co.country_isocode
group by sg_gameno, sg_end, sg_hostcity, country_olympic_name
is syntactically valid. Whether it provides you the results you want is another question-- you'd need to tell us what your tables look like, what data is in them, what result you want, etc.

In Oracle, you can't have aggregate functions and individual columns in the SELECT list, unless the individual columns are included in GROUP BY clause.
You can use RANK or DENSE_RANK function to rank the records based on thet year and then select the from the resultset the top ranked rows.
select * from (
select sg_gameno, sg_Year, sg_end, sg_hostcity, country_olympic_name,
rank() over (order by sg_year desc) as ranking
from Summergames s, Country co
where s.country_isocode = co.country_isocode
)
where ranking = 1;
You can also use following query to get the same result. You will have to select the one that performs best for you.
select sg_gameno, sg_Year, sg_end, sg_hostcity, country_olympic_name
from Summergames s, Country co
where s.country_isocode = co.country_isocode
and sg_Year = (select max(sg_Year)
from Summergames s, Country co
where s.country_isocode = co.country_isocode);

Related

SQL What do I need to group by?

I am trying to get a better understanding of group by and count in SQL and tried to find the student who has been studying for the second longest time.
I need to also group by s.semester for it to work, just group by s.name alone (which is what I had done initially) does not work - why is this? I know this is right, but am trying to understand why for future practice questions.
select s.name
from students s
group by s.name, s.semester
having 1 = (select count (gold.name)
from students gold
where gold.name <> s.name
and gold.semester > s.semester
)
Thanks in advance!
To solve this task, it is not enough to use grouping. You need to use ranking functions.
You will receive the rank of each subsequent student or students, based on the number of semesters.
You can get students by rank using "where".
select
*
from(
select
row_number() over (partition by name_students, semestr order by semestr_count
asc) r_n,
name_students,
semestr
from (
select name_students, semestr, count(semestr_count) from studies
group by name_students, semestr
) agregate_studies
where r_n = 1
Using r_n for get some students top _ n : 2..3

Get the first 3 elements for each value of an attribute SQL

I'm using the mondial database that can be queried here http://www.semwebtech.org/sqlfrontend/
I am trying to get the 3 religion that are most praticed on each continent I've come up with this:
select religion.name, sum(religion.percentage) as total, continent
from religion join encompasses on religion.country = encompasses.country
group by name, continent order by continent, total DESC
This gives me a list of each religion with for each continent ordered by their popularity but how do I get the first 3 results for each continent ?
I have looked up cursor but I don't see how to apply them to my case and it looks like there is a simple answer
I would use window functions:
select rc.*
from (select r.name, sum(r.percentage) as total, e.continent,
row_number() over (partition by e.continent order by sum(r.percentage) as total desc) as seqnum
from religion r join
encompasses e
on r.country = e.country
group by r.name, e.continent
) rc
where seqnum <= 3;
Having explained how to modify your query to answer the question, let me now point out that your query is wrong. The sum of the percentage of people is not the same as the total number of people. For instance, I think Bhutan is pretty close to 100% Buddhist (Buddhism is the state religion). But there are more Buddhists in India (~0.7% Buddhist, according to one source).

SQL Query: Find the name of the company that has been assigned the highest number of patents

Using this query I can find the Company Assignee number for company with most patents but I can't seem to print the company name.
SELECT count(*), patent.assignee
FROM Patent
GROUP BY patent.assignee
HAVING count(*) =
(SELECT max(count(*))
FROM Patent
Group by patent.assignee);
COUNT(*) --- ASSIGNEE
9 19715
9 27895
Nesting above query into
SELECT company.compname
FROM company
WHERE ( company.assignee = ( *above query* ) );
would give an error "too many values" since there are two companies with most patents but above query takes only one assignee number in the WHERE clause. How do I solve this problem? I need to print name of BOTH companies with assignee number 19715 and 27895. Thank you.
You have started down the path of using nested queries. All you need to do is remove COUNT(*):
SELECT company.compname
FROM company
WHERE company.assignee IN
(SELECT patent.assignee
FROM Patent
GROUP BY patent.assignee
HAVING count(*) = (SELECT max(count(*))
FROM Patent
GROUP BY patent.assignee
)
);
I wouldn't write the query this way. The use of max(count(*)) is particularly jarring, but it is valid Oracle syntax.
Applying an aggregate function on another aggregate function (like max(count(*))) is illegal in many databases but I believe using the ALL operator instead and a join to get the company name would solve your problem.
Try this:
SELECT COUNT(*), p.assignee, c.compname
FROM Patent p
JOIN Company c ON c.assignee = p.assignee
GROUP BY p.assignee, c.compname
HAVING COUNT(*) >= ALL -- this predicate will return those rows
( -- for which the comparison holds true
SELECT COUNT(*) -- for all instances.
FROM Patent -- it can only be true for the highest count
GROUP BY assignee
);
Assuming you have Oracle, I thought about this a bit differently:
select
c.compname
from
company c
join
(
select
assignee,
dense_rank() over (order by count(1) desc) rnk
from
patent
group by
assignee
) p
on p.assignee = c.assignee
where
p.rnk = 1
;
I like this because is lets you find the any rank. For example, if you want the top 3 you would just change p.rnk = 1 to p.rnk <= 3. If you want 10th place, you just change it to p.rnk = 10. Adding the total count and rank into the results would be easy from here too. Overall I think it's more versatile.

SQL return based on Aggregate Function

I have this query that works, but it returns information for all cities and I only want to return based on the max population in the city for each row for one country but aggregate functions can't be used in the where clause. How can I limit my results to one per country?
SELECT lab6.country.name, max(lab6.city.population) AS largest_pop
FROM lab6.country, lab6.city
WHERE lab6.country.country_code = lab6.city.country_code
GROUP BY lab6.country.name, lab6.city.name"
PostgreSQL supports window functions that you can take advantage with.
SELECT countryName, cityName, largest_pop
FROM
(
SELECT a.name countryName,
b.name cityName,
b.population AS largest_pop,
DENSE_RANK() OVER (PARTITION BY a.name
ORDER BY b.population DESC) rn
FROM lab6.country a, lab6.city b
WHERE a.country_code = b.country_code
) x
WHERE rn = 1
Window Functions
Maybe I'm misunderstanding but do you just want to return the largest city in each country?
If so, you simply can group by country, instead of by country and city. You'll need to include the attribute that identifies a country, and the name of that country in your GROUP BY statement. Your query will end up looking like:
SELECT lab6.country.name AS cName, max(lab6.city.population) AS largest_pop
FROM lab6.country, lab6.city
WHERE lab6.country.country_code = lab6.city.country_code
GROUP BY lab6.country.country_code, lab6.country.name
If you want to also include the name of the largest city, you'll first need to decide what to do if there are multiple largest cities (countries where there are two or more cities with the same, largest, population). I'm going to assume you're okay with including them all. In that case, you can simply do a sub-query in your FROM clause, joined on cities with the same population:
SELECT lc.cName, lab6.city.name, lc.largest_pop
FROM (
SELECT lab6.country.country_code AS cCode
lab6.country.name AS cName,
max(lab6.city.population) AS largest_pop
FROM lab6.country, lab6.city
WHERE lab6.country.country_code = lab6.city.country_code
GROUP BY lab6.country.country_code, lab6.country.name
) AS lc
JOIN lab6.city ON lc.cCode = lab6.city.country_code
WHERE lab6.city.population = lc.largest_pop

SQL ORDER BY with column number or aggregate function

I've got 2 different results when I try ORDER BY with column number and with an aggregate function. What is the difference between these 2 methods? ( I thought they'd have the same output)
List the 1978 films by order of cast list size. There're 3 tables below:
movie(id, title, yr, director)
actor(id, name)
casting(movieid, actorid, ord)
Answer 1 using ORDER BY with column number:
SELECT title
,COUNT(a.id)
FROM movie m
,casting c
,actor a
WHERE m.id=movieid
AND a.id=actorid
AND yr=1978
GROUP BY title
ORDER BY 2 DESC
Using COUNT(a.id). Everything is the same except the last line
...
ORDER BY COUNT(a.id) DESC
I would suggest you to make a subquery and order that for the clean result
I think Jester has it. Here's an example for you:
select title, actor_count from (
SELECT title
,COUNT(a.id) actor_count
FROM movie m
,casting c
,actor a
WHERE m.id=movieid
AND a.id=actorid
AND yr=1978
GROUP BY title) subquery
order by actor_count