I'm new to SQL and facing following problem:
This is my table:
name city people
-----|-----|--------|
John | A | 5 |
Ben | D | 6 |
John | A | 5 |
Ben | A | 5 |
John | B | 8 |
Ben | D | 6 |
I want to group by the name and receive associated to the name that city with the largest quantity. As a second query, instead of the largest quantity, that city with the highest sum of inhabitants.
This would be the outcome for the first query:
name city
-----|-----|
John | A |
Ben | D |
Thank you!
I don't know exactly what you mean by "to the name that city with the largest quantity". What I understood was you sum the column 'people' per couple (name, city), thus (John, A) would be 10 and (John, B) would be 8, and you take the max value to get (John, A).
In this case, you can do it this way:
SELECT
name,
city
FROM
(SELECT
name,
city,
SUM(people) AS tot
FROM table
GROUP BY name, city
ORDER BY name ASC, tot DESC) AS a
GROUP BY name ;
As for the city with the largest number of inhabitants, you just have to group by city and sum the column people and take the max:
SELECT
city,
SUM(people) AS nb_inhabitants
FROM table
GROUP BY city
ORDER BY nb_inhabitants DESC
LIMIT 1;
SELECT name, city, sum( people )
FROM `detail`
GROUP BY name
ORDER BY people ASC
LIMIT 0 , 30
I am not really understand what your are expecting ,but I guess you want to do this thing.
Description : I am group by people from there name , and got sum of the people and make them ASC order. I am not sure your are expect this thing.
You can also , group people by their city
SELECT name, city, sum( people )
FROM `detail`
GROUP BY city
ORDER BY people ASC
LIMIT 0 , 30
If this not you expect , Please , further describe question ,we will try to give some answer.
Try this, I have tried by making a table as per your sample data,
CREATE TABLE KaiTable
(
NAME VARCHAR(50)
,city CHAR(1)
,people INT
);
INSERT INTO KaiTable
VALUES
(
'John'
,'A'
,5
),
('Ben ' ,'D' ,6),
('John' ,'A' ,5),
('Ben ' ,'A' ,5) ,
('John' ,'B' ,8) ,
('Ben ' ,'D' ,6)
SELECT NAME,city
FROM
(SELECT NAME,city,SUM(people) AS PeopleSum
FROM KaiTable
GROUP BY NAME, city
ORDER BY NAME ASC, PeopleSum DESC) AS a
GROUP BY NAME DESC;
SQL Fiddle Demo
Related
How do I get the id of MAX(name)? The id I get from below query doesn't correspond to the row where MAX(name) is in.
SELECT id, MAX(name) from table group by country
id name country
+---+-----------+---------+
| 1 | John | USA |
+---+-----------+---------+
| 2 | Joe | CHINA |
+---+-----------+---------+
| 3 | Jonah | USA |
+---+-----------+---------+
| 4 | Jonathan | USA |
+---+-----------+---------+
Edit:
The purpose is to get the longest name in every country. So from the table, I'd like to see the result to be id 2 and 4.
You can do it with variables, and self joins, and depending on your version of sql window functions, but you can also do some string manipulation.
SELECT country,
SUBSTRING_INDEX(ids, ',', 1) AS id
FROM (
SELECT country,
GROUP_CONCAT(id ORDER BY LENGTH(NAME) DESC) AS ids
FROM table
GROUP BY country
) z
Also, max(name) won't get you the one with the longest name, it will get you the one closest to the end of the alphabet.
You can also try (assuming you need to account for the possibility of more than one name per country having the same max length):
SELECT z.country, z.id
FROM table z
JOIN (
SELECT country, MAX(LENGTH(name)) AS maxLen
FROM table
GROUP BY country
) lens ON (lens.country = z.country AND lens.maxLen = LENGTH(z.name))
Use a subselect:
SELECT id, country
FROM table
WHERE (country, CHAR_LENGTH(name)) IN (SELECT country, MAX(CHAR_LENGTH(name))
FROM table
GROUP BY country)
GROUP BY country
Note, however, that there may be more than one row returned if there are more than one records having this length of the name!
I have an table like that:
id | name | v (lvl)
11 | Jane | 6
12 | John | 5
13 | Jane | 6
14 | John | 5
15 | Jane | 7
16 | Jane | 5
In my autocomplete form now id like to group the names but get the last value (value with biggest id). In the example above would be
Jane | 5
I tried with combinations like distinct, group by, order by. But im always get
Jane | 6
or grouped like this and reversed:
Jane | 6
Jane | 7
Jane | 5
I would need something like this:
SELECT name,lvl FROM
(
SELECT DISTINCT name, lvl FROM pora WHERE name LIKE 'Jane' ORDER BY lvl DESC
)
GROUP BY name
EDIT: I won't get the highest lvl, i want get the lvl of the highest id, grouped by name. Thats all. My example above would be the best explanation what i like to get.
In the inner query i change the order to DESC for all and in the outer i group it by names. But i get an error for this.
EDIT 2 I finally did at my own. The correct solution (i was already close):
SELECT a.name, a.lvl FROM
(
SELECT DISTINCT name, lvl FROM pora WHERE name LIKE 'Jane' ORDER BY id DESC
)as a
GROUP BY name
LIKE without % is just =
SELECT *
FROM yourTable
WHERE name = 'Jane'
ORDER BY id DESC
LIMIT 1
But because you mention autocomplete functionality you should use:
WHERE name LIKE 'Jane%'
To have the latest, you need to have a field dateAdded which stores the date you ran the insert command.
Following which, you use MAX(dateAdded) to get the latest ID (since, as you mentioned, it may decrease as well)
UPDATE:
if ID doesn't decrease, you can always use MAX(ID)
SELECT MAX(id), v from tablename where name = 'Jane'
UPDATE:
This has been tested:
SELECT ID, v from tableName where ID = (SELECT MAX(ID) as ID from tableName where name like '%Jane%')
Try the following query (h/t #lamak)
WITH CTE AS
(
SELECT *,
RN = ROW_NUMBER() OVER(PARTITION BY name
ORDER BY [id] DESC)
FROM poro
)
SELECT *
FROM CTE
WHERE RN = 1
I have a table with three columns,
| User_id (INT) | CountryCode (VARCHAR) | channel_accessed (VARCHAR) |
There is no primary key over here, so repetition is possible for all columns.
I want to write a SQL query that returns Top countries name & there corresponding count w.r.t unique User_id
Tried following this Using group by on multiple columns but this has not helped me much.
sample data :
| User_id (INT) | CountryCode (VARCHAR) | channel_accessed (VARCHAR) |
1 US ARY
2 CA ARY
3 CA MTV
2 CA HUMTV
4 US Tensports
5 US Star Sports
2 CA PTV
2 CA QTV
2 CA NATGEO
Expected Result : US, because it has more unique users.
Try this:
select CountryCode
from yourtable
group by CountryCode
order by count(distinct User_id) desc
limit 1
SQLFiddle Demo
If the channel_accessed column doesn't matter then you could try
SELECT CountryCode, MAX(user_count)
FROM (SELECT CountryCode,
COUNT(DISTINCT(user_id)) as user_count
FROM table_name
GROUP BY CountryCode)
There are countries in MySQL table:
id | title
1 | USA
2 | Spain
3 | Italy
4 | Canada
I need to select Italy on the top of list and other countries sorted by title below.
But 'order by' doesn't work.
(SELECT * FROM countries WHERE id = 3) UNION (SELECT * FROM countries WHERE id != 3 ORDER BY title)
First sort your data based on whether it is Italy or not, getting Italy first. Then sort based on the title.
SELECT * FROM countries
ORDER BY title='Italy' DESC, title
(The only trick you have to know -- or experiment with -- is that FALSE comes before TRUE, and hence the DESC in the code. I guess that makes sense if you convert them to 0 < 1.)
you can try this
SELECT * FROM countries
ORDER BY case when id !=3 then `title` end asc ,
case when id =3 then `title` end asc ;
SELECT * FROM countries WHERE id = 3
union
SELECT c.* FROM (SELECT * FROM countries WHERE id != 3 order by title) c
I apologize for the confusing title, I can't figure out the proper wording for this question. Instead, I'll just give you the background info and the goal:
This is in a table where a person may or may not have multiple rows of data, and those rows may contain the same value for the activity_id, or may not. Each row has an auto-incremented ID. The people do not have a unique identifier attached to their names, so we can only use first_name/last_name to identify a person.
I need to be able to find the people that have multiple rows in this table, but only the ones who have multiple rows that contain more than one different activity_id.
Here's a sample of the data we're looking through:
unique_id | first_name | last_name | activity_id
---------------------------------------------------------------
1 | ted | stevens | 544
2 | ted | stevens | 544
3 | ted | stevens | 545
4 | ted | stevens | 546
5 | rachel | jameson | 633
6 | jennifer | tyler | 644
7 | jennifer | tyler | 655
8 | jennifer | tyler | 655
9 | jack | fillion | 544
10 | mallory | taylor | 633
11 | mallory | taylor | 633
From that small sample, here are the records I would want returned:
unique_id | first_name | last_name | activity_id
---------------------------------------------------------------
dontcare | ted | stevens | 544
dontcare | jennifer | tyler | 655
Note that which value of unique_id gets returned is irrelvant, as long as it's one of the unique_ids belonging to that person, and as long as only one record is returned for that person.
Can anyone figure out how to write a query like this? I don't care what version of SQL you use, I can probably translate it into Oracle if it's somehow different.
I would do:
SELECT first_name, last_name, COUNT(DISTINCT activity_id)
FROM <table_name>
GROUP BY first_name, last_name
HAVING COUNT(DISTINCT activity_id) > 0;
I'll build through the logic with you. First, lets find all people that have more than one entry:
Unique list of name + activity ID:
select first_name, last_name,activity_id, count(1)
from yourtable
group by first_name, last_name,activity_id
Now we'll turn that into a subquery and look for users with more than 1 activity_ID
Select first_name, last_name
from
(select first_name, last_name,activity_id, count(1)
from yourtable
group by first_name, last_name,activity_id) a
group by first_name, last_name
having count(1) > 1
Should work as that...I didn't return an activity_id, adding max(activity_id) to the select statement will grab the highest one.
Note that which value of unique_id gets returned is irrelvant, as long as it's one of the unique_ids belonging to that person, and as long as only one record is returned for that person.
These querys should do the trick. there is no need for distinct keywords or an subquery to fetch the results BumbleShrimp needs (if BumbleShrimp needed the correct unique_id also an subquery is needed to match the right value)
Below is the most simple query i could think off that should work, but it could be slow on large tables.
SELECT
first_name
, last_name
, activity_id
FROM
person
GROUP BY
first_name
, last_name
, activity_id
HAVING COUNT(*) >= 2
Could be slow because explain shows "Using index; Using temporary; Using filesort".
Using temporary could trigger an disk based temporary table so we make use off an inner self join to remove the need of an Using temporary.
SELECT
person1.first_name
, person1.last_name
, person1.activity_id
FROM
person person1
INNER JOIN
person person2
ON
person1.unique_id < person2.unique_id
AND
person1.first_name = person2.first_name
AND
person1.last_name = person2.last_name
AND
person1.activity_id = person2.activity_id
ORDER BY
activity_id asc
See demo http://sqlfiddle.com/#!2/fe3ba/29
Side note the inner join will fail if there are three or more duplicates
see demo http://sqlfiddle.com/#!2/1ff33/15
New query
SELECT
first_name
, last_name
, activity_id
FROM
person
GROUP BY
activity_id
, last_name
, first_name
HAVING COUNT(activity_id) >= 2
ORDER BY
activity_id asc
see demo http://sqlfiddle.com/#!2/1e418/3 fixes the three or more duplicates problem / orders activity_id right and can be used on large tables because there is not need off a temporary table what can slow down the execution
To get only the names, the simplest is:
SELECT
first_name
, last_name
FROM
person
GROUP BY
first_name
, last_name
HAVING
COUNT(DISTINCT activity_id) >= 2 ;
To get one row for every name, you can use window function (work fine in Oracle):
WITH cte AS
( SELECT
unique_id, first_name, last_name, activity_id
, COUNT(DISTINCT activity_id) OVER (PARTITION BY last_name, first_name)
AS cnt
, MIN(unique_id) OVER (PARTITION BY last_name, first_name)
AS min_id
FROM
person
)
SELECT
unique_id, first_name, last_name, activity_id
FROM
cte
WHERE
cnt >= 2
AND
min_id = unique_id ;
Instead of MIN(unique_id) OVER ..., you could use MIN(activity_id) OVER ... (or MAX()) and accordingly min_id = activity_id. Or ROW_NUMBER() function. Since you need the COUNT(DISTINCT activity_id) anyway, let me add this version.
With an index on (last_name, first_name, activity_id, unique_id) it should be quite efficient:
WITH cte AS
( SELECT
unique_id, first_name, last_name, activity_id
, COUNT(DISTINCT activity_id) OVER (PARTITION BY last_name, first_name)
AS cnt
, ROW_NUMBER() OVER (PARTITION BY last_name, first_name
ORDER BY activity_id, unique_id)
AS rown
FROM
person
)
SELECT
unique_id, first_name, last_name, activity_id
FROM
cte
WHERE
cnt >= 2
AND
rown = 1 ;
Tested at SQL-Fiddle