Trouble with Group By and Having in SQL - mysql

I am trying to learn Group By and Having but I can't seem to understand what happened here. I used w3shools SQL Tryit Editor.
The table I created is:
name age country
------------------------
Sara 17 America
David 21 America
Jared 27 America
Jane 54 Canada
Rob 32 Canada
Matthew 62 Canada
The Query I used:
select
sum(age), country
from
NewTable
group by
country
having
age>25;
I expected the query to categorize the information by country and use age>25 filter to create the results but here is the output:
sum(age) country
--------------------
65 America
148 Canada
What happened?! The result is sum of American and Canadian people in all ages.

The piece you're missing is specific to the having keyword. Using the having clause in your query is applied to the dataset after the grouping occurs.
It sounds like you are expecting the records with age less than 25 to be excluded from your query before grouping occurs. But, the way it works is the having clause excludes the total age for each group that sums to a total over 25.
If you want to exclude individual records before totaling the sum of the age, you could do something like this (using a where clause which is applied prior to grouping):
select sum(age), country from NewTable where age > 25 group by country;

A where clause puts a condition on which rows participate in the results.
A having clause is like a where, but puts a condition on which grouped (or aggregated) values participate in the results.
Either, try this:
select sum(age), country
from NewTable
where age > 25 -- where puts condition on raw rows
group by country
or this:
select sum(age), country
from NewTable
group by country
having sum(age) > 25 -- having puts a condition on groups
depending on what you're trying to do.

Related

Fetch fixed set of duplicate records from table

I want to fetch records from a table that contains duplicate records. I want the output to be like only two duplicate records from each set of duplicate records in overall record output set.
example-
Name
Country
John
India
Mark
India
Chris
Russia
Feggy
England
Rain
Russia
Monesy
Russia
Bhumi
India
Peter
England
Bruice
England
Radhe
India
Output should have only two duplicate set of records from all duplicate of similar type as we can see in output below the country is repeating only two times and it took only first two counters of duplicate records in final record set -
Name
Country
John
India
Mark
India
Chris
Russia
Feggy
England
Rain
Russia
Peter
England
You can number the lines by the window and select only the first N.
Sorting should be chosen according to the business logic of the query.
For example:
;WITH numbered_name AS
(
SELECT *
, ROW_NUMBER() OVER (PARTITION BY t.Country ORDER BY t.Name) rn
FROM table t
)
SELECT Name
, Country
FROM numbered_name
WHERE rn <= 2

How to fix 'An aggregate may not appear in the WHERE clause' error in MS SQL Server

For a school project, i need to create some databases in MS SQL Server , create some views, and manage the users acces. The thing is that our course was really empty, and i'm having trouble with some mechanics of MS SQL Server
I have a table with every player of the football world cup of 2018, and i want to take the 20 shortest players, so i just wanted to use ORDER BY Person.Height. If i use that, my result is something like that :
62 165 Panama QA19
63 165 SaudiArabia AY8
78 165 Switzerland SX23
59 166 Mexico AJ20
etc...
but i just want to take the shortest players and order them by country, not by height, so having something like that
69 168 Argentina SE18
66 168 Argentina LM15
67 166 Brazil CF22
64 169 Brazil RF18
the 20 shortest players ordered by country in an alphabetical order
This is the code i have right now, and this give me the first result
SELECT TOP (20) Person.Weight, Person.Height, Country.NameCountry,
LEFT(Person.Name, 1)+LEFT(Person.FirstName, 1)+CAST(Player.Numero AS
nvarchar(MAX)) AS Initiales
FROM Person INNER JOIN Country
ON Person.CountryId = Country.CountryID
INNER JOIN Player
ON Person.PersonID = Player.PersonID
WHERE -----------------
ORDER BY Person.Height, Country.NameCountry
If i use MIN(Person.Height) in the WHERE clause, i have this error : An aggregate may not appear in the WHERE clause unless it is in a subquery contained in a HAVING clause or a select list, and the column being aggregated is an outer reference.
But i don't need any HAVING OR GROUP BY clause, so i don't really understand what i'm supposed to do.
I know that my explanation is not very clear, but if somebody could help me with that, that would be vey nice
Try with a subquery
SELECT * FROM (
SELECT Person.Weight, Person.Height, Country.NameCountry,
LEFT(Person.Name, 1)+LEFT(Person.FirstName, 1)+CAST(Player.Numero AS
nvarchar(MAX)) AS Initiales
FROM Person INNER JOIN Country
ON Person.CountryId = Country.CountryID
INNER JOIN Player
ON Person.PersonID = Player.PersonID
WHERE -----------------
ORDER BY Person.Height
LIMIT 0,20)
ORDER NameCountry

Get row position within a series of records in mysql

I have the following rows within a table.
MatchIDAuto CompetitionIDAuto TeamHome TeamAway MatchDate
4770 65 New Zealand South Africa 2017-02-19
4771 65 New Zealand South Africa 2017-02-21
4772 65 New Zealand South Africa 2017-02-25
4773 65 New Zealand South Africa 2017-03-01
4774 65 New Zealand South Africa 2017-03-04
What I need to be able to do is when I do the following:
select * from Match2 where MatchIDAuto=4772
Is know that it is the 3rd Match in the series. How could I dynamically calculate that with the query?
Without an ORDER BY clause there is no guarantee that row with id 4772 is the third row in the serie. That is because the database without an order by clause MAY generate different orders accordingly the Execution Plan.
So the first thing to do is to add an order by clause to your query. By the data it could be MatchIDAuto or MatchDate that I will leave by your choice. The query in MySql to get you the order number of a row will be:
select *
from (
select m.*,
#ord:=#ord+1 roworder
from Match2 m,
(select #ord:=0) t
ORDER BY MatchDate
) sub
where MatchIDAuto=4772;
This will return every column plus roworder with the order 3. On this query I choose the MatchDate field since, to me makes more sense on your data to be the column of your order by.
This technique will create a variable and sums it up to every row. You just wrap it in a subquery and query it.

How to get results from Mysql database using WHERE if there is more than 1 criterion for identification?

id points year country
-----------------------------------
1 45 1998 Mexico
2 45 2000 Germany
3 47 2010 Russia
4 45 1970 China
5 49 2010 Austria
I wonder how can I take row results considering only 2 items from country column. For example only records where country is Germany and Mexico. When I try to get results where only 1 country is criterion the thing is easy:
SELECT * FROM List WHERE Country='Mexico';
the result is:
id points year country
-----------------------------------
1 45 1998 Mexico
but when I try to get results where 2 country items are criteria problems start. I tried:
SELECT * FROM List WHERE country='Mexico' AND Country='Germany';
SELECT * FROM List WHERE country='Mexico' AND 'Germany';
SELECT * FROM List WHERE country='Mexico','Germany';
SELECT * FROM List WHERE country='Mexico'AND WHERE country='Germany';
but no desired result:
id points year country
-----------------------------------
1 45 1998 Mexico
2 45 2000 Germany
I understand that maybe I committed logical error because there is no single record where country is Mexico and Germany at same time, and sql maybe understands claim exactly that way, but, how to write correctly in sql language: Give me results for records where countries are Mexico and Germany. Thanks.
You are looking for IN operator
SELECT * FROM List WHERE Country in ('Mexico','Germany');
Just use OR.
So instead of
SELECT * FROM List WHERE country='Mexico' AND Country='Germany';
it would be
SELECT * FROM List WHERE country='Mexico' OR country='Germany';
IN is also a good function to use, especially if you've got multiple values that you want to check against but that's been covered in the other answers.
You need to use or or in, you have been using and and asking mysql to find a row where country is both Mexico and Germany which is not true.
SELECT * FROM List WHERE Country in ('Mexico','Germany');
try this:
SELECT * FROM List WHERE country='Mexico' OR Country='Germany';
SQL is using logic. Natural language is not.
When you say that you want the results for a list of countries you need to specify so. This request corresponds to an logical or. Since the name can be one or the other, both are correct.
SELECT * FROM List WHERE Country = 'Mexico' OR Country = 'Germany'
To prevent further mistakes like these, I recommend that you look up logical operations in the docs (they are very good). MySQL or the PostGres, both should be fine.

Extract values of a sorted request with SQL

I have this sql table with people's name and ages.
Bob 28
Bryan 30
Jim 25
John 42
Bill 22
Sam 28
Tom 26
I would like to make a sql command to order all people by age desc, find a name in it, a return the preceding one, the founded and the next one with their position.
For example, admit that I would like to find Tom, my request should return :
Name Age Rank
Jim 25 2
Tom 26 3
Bob 28 4
Jim has the number 2 because Bill is the youngest
Is it possible to do something like this ?
Thanks in advance for any help
SQL isn't suited for row-based operations. There's no easy way to do "find a row where some condition(s) = true, then return the previous row" in a single query. You can do it in a couple steps, though:
a) Run one query to retrieve 'Tom' and his age (26).
b) Run another query to get the next older person
SELECT name, age FROM ... WHERE age > 26 ORDER BY age ASC LIMIT 1
c) Repeat but for next younger:
SELECT name, age FROM ... WHERE age < 26 ORDER BY age DESC LIMIT 1
This'll fetch people who are at least 1 year old/younger... You don't specify what happens if there's multiple people of the same age (e.g. There's Fred who's also 26, or Doug and Elmer who are both 25), so I'm ignoring those conditions.