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)
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 two similar tables, they have the same columns, but different data, both matching different criterions. I want to join Table A to Table B, where some of the values are null.
I tried to look up similar questions but they are not describing my case as far as i can tell.
As an example:
Table A looks like
| id | name | age | gender |
1 Jhon 2 Male
2 Will null null
Table B looks like
| id | name | age | gender |
1 Jhon null null
2 Will 3 Male
What i would like to make is like
| id | name | age | gender |
1 Jhon 2 Male
2 Will 3 Male
I was trying to left join it, but the result is not as expected. My thought maybe i need to inner join it, then left join maybe, but it is a bit blurry yet.
I'm kinda new to joins, so every thought is appreciated.
Thanks in advance.
You can try to use UNION ALL in the subquery to do MAX
SELECT id ,name,MAX(age) age ,MAX(gender) gender
FROM (
SELECT id ,name , age , gender
FROM A
UNION ALL
SELECT id ,name , age , gender
TABLE B
) t1
GROUP BY id ,name
If your A and B tables schema are the same I would suggest you use only one table and use a flag to split those two part.
Did you try this?
select id, name,
coalesce(a.age, b.age) as age,
coalesce(a.gender, b.gender) as gender
from a join
b
using (id, name);
The issue is less the type of join then in how you combine the values from the two tables in the select.
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
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
In mp_cities table city_name and city_id are the fields
city_id city
--------------------
1 Chennai
2 Bangalore
3 Kerala
In profile table
user_email city_type
------------------------------
abc#gmail.com 1,2,3
I am using the following query
SELECT city_name
FROM mp_cities
WHERE city_id IN (SELECT city_type
FROM profile
WHERE user_email='abc#gmail.com')
this query will result Chennai.
I have to get all the cities
You can use FIND_IN_SET() in MySQL.
SELECT a.*
FROM mp_cities a
INNER JOIN profile b
ON FIND_IN_SET(a.city_id, b.city_type)
WHERE b.user_email = 'abc#gmail.com'
but the best way so far I can think is to normalize the table properly.
mp_cities
city_id (PK)
city
other columns
profile
user_id (PK)
other columns
mp_cities _profile
city_id (FK)
user_id (FK)
You would get the desired result if the profile table looked like this:
user_email city_type
------------------------
abc#gmail.com 1
abc#gmail.com 2
abc#gmail.com 3
That is, the inner SELECT must return several rows, each with a number, NOT one row with a comma-delimited set of numbers.
Try to join both tables with FIND_IN_SET() function like this:
SELECT c.*
FROM mp_cities c
JOIN profile p
ON FIND_IN_SET(c.city_id,p.city_type) > 0;
See this SQLFiddle