How can I to get distinct results of the last ten visitors, with a count of how many times they've visited?
This:
SELECT DISTINCT all_ref FROM site_stats WHERE all_ref!='' ORDER BY id DESC LIMIT 10";
returns last ten most recent visitors
all_ref
Chicago, IL
Chesapeake, VA
Austin, TX
San Jose, CA
Houston, TX
Newport News, VA
Sebastian, FL
Dublin, IE
Menlo Park, CA
Waves, NC
This will return the count for all visitor:
SELECT all_ref, COUNT(*) AS ct FROM site_stats WHERE all_ref!=''
AND all_ref!=',' GROUP BY all_ref ORDER BY ct DESC, all_ref
This is what I'm tryng to get the last 10 visitors with how many times they've visited:
SELECT x.all_ref, x.ct
FROM (SELECT all_ref, COUNT(*) AS ct FROM site_stats WHERE all_ref!='' GROUP BY all_ref )
AS x LEFT JOIN site_stats AS f
ON f.all_ref=x.all_ref
ORDER BY f.id DESC LIMIT 10
It returns this (the all_ref and ct values returned ARE correct):
all_ref ct
Chicago, IL 26
Chicago, IL 26
Chesapeake, VA 18
Chesapeake, VA 18
Austin, TX 2
San Jose, CA 3
Houston, TX 1
Chicago, IL 26
Chicago, IL 26
Chicago, IL 26
but should return something more like this:
all_ref ct
Chicago, IL 26
Chesapeake, VA 18
Austin, TX 2
San Jose, CA 3
Houston, TX 1
Chicago, IL 26
Pittsburgh, PA 11
Richmond, VA 52
Waves, NC 24
Grandy, NC 9
Making it DISTINCT x.all_ref is not the answer.
UPDATE:
The solution that works for me:
SELECT x.all_ref, x.ct
FROM (SELECT all_ref, MAX(id) AS id, COUNT(*) AS ct
FROM site_stats
WHERE all_ref!='' GROUP BY all_ref )
AS x LEFT JOIN site_stats AS f
ON f.all_ref=x.all_ref
GROUP BY x.all_ref
ORDER BY x.id DESC LIMIT 10;
You may first find the distinct then join the table -
SELECT f.id
,x.all_ref
,x.ct
FROM (SELECT all_ref
,COUNT(*) AS ct
FROM site_stats
WHERE all_ref!=''
GROUP BY all_ref ) AS x
LEFT JOIN (SELECT DISTINCT id, all_ref
FROM site_stats) AS f ON f.all_ref=x.all_ref
ORDER BY f.id DESC LIMIT 10
Just to let you know, this was the implementation of COUNT window function. If you MySQL version supports Window function, you may simply use -
SELECT DISTINCT id
,all_ref
,COUNT() OVER() AS ct
FROM site_stats
WHERE all_ref!=''
ORDER BY id DESC LIMIT 10
The solution that works for me:
FROM (SELECT all_ref, MAX(id) AS id, COUNT(*) AS ct
FROM site_stats
WHERE all_ref!='' GROUP BY all_ref )
AS x LEFT JOIN site_stats AS f
ON f.all_ref=x.all_ref
GROUP BY x.all_ref
ORDER BY x.id DESC LIMIT 10;
Related
So I have the next code:
SELECT distinct NVL( l.city, ' '), e.last_name || ' ' || e.first_name
FROM locations l
FULL JOIN departments d
ON d.location_id = l.location_id
FULL JOIN employees e
ON e.department_id = d.department_id
OUTPUT:
NVL(L.CITY,'') E.LAST_NAME||''||E.FIRST_NAME
------------------- ----------------------------------------------
1) Seattle
2) Seattle Kochhar Neena
3) Oxford Zlotkey Eleni
4) Oxford Abel Ellen
5) Oxford Vargas Jonathon
6) Oxford Grovlin Gus
I want it to not display the line where is only City and no Lastname if there is a line where this city is mentioned. For example, I have row
Seattle Kochhar Neena
because Seattle is already displayed, I don't want to see the first line. However, if there is no row with city and last_name, there should be line with just the city.
Any idea how to do it?
A little bit of analytic sql should do the trick.
SQL> with your_data as
2 (
3 SELECT distinct
4 l.city city,
5 e.last_name || ' ' || e.first_name name
6 FROM hr.locations l FULL JOIN
7 hr.departments d ON d.location_id = l.location_id FULL JOIN
8 hr.employees e ON e.department_id = d.department_id
9 )
10 select *
11 from
12 (
13 select
14 y.*,
15 count(*) over ( partition by city ) as seq
16 from your_data y
17 )
18 where seq = 1 or ( seq > 1 and name != ' ' )
19 order by 1,2;
CITY NAME SEQ
------------------------------ ---------------------------------------------- ----------
Beijing 1
Bern 1
Bombay 1
Geneva 1
Hiroshima 1
London Mavris Susan 1
Mexico City 1
Munich Baer Hermann 1
Oxford Abel Ellen 34
Oxford Ande Sundar 34
Oxford Banda Amit 34
Oxford Bates Elizabeth 34
Oxford Bernstein David 34
Full tutorial on these techniques here https://www.youtube.com/watch?v=0cjxYMxa1e4&list=PLJMaoEWvHwFIUwMrF4HLnRksF0H8DHGtt
Use row_number analytical function based on pks.
Select city, ename from
(SELECT distinct NVL( l.city, ' ') as city,
trim(e.last_name || ' ' || e.first_name) as ename,
Row_number() over
(partiotion by l.location_id order by e.department_id desc nulls last) as rn
FROM locations l
FULL JOIN departments d
ON d.location_id = l.location_id
FULL JOIN employees e
ON e.department_id = d.department_id)
Where case when ename is null and rn != 1
Then 0 Else 1
End = 1
Cheers!!
I have a table that looks like this:
id name yearofstudy mark
1 Alain A 2 75
2 Michael B 3 85
3 Chen C 1 55
4 Caroline D 2 60
5 Mohamed E 2 60
6 Alex F 1 55
7 Sofia O 3 78
8 Samir O 1 85
9 Rob G 2 78
10 Big K 3 55
And I'm trying to get the id, name, year and mark of the students with the lowest (and highest) mark in each year which would give:
id name yearofstudy mark
3 Chen C 1 55
4 Caroline D 2 60
10 Big K 3 55
SQL isn't my strong point and I've been trying using the MIN() function but I haven't managed to get it right yet and would really appreciate some help.
Using a subquery to get the min() and max() for each yearofstudy, and joining it to the original table. (You did say you wanted lowest and highest, right?)
select t.id, t.name, t.yearofstudy, t.mark
from t
inner join (
select
yearofstudy
, min(mark) as minMark
, max(mar) as maxMark
from t
group by yearofstudy
) as m
on t.yearofstudy = m.yearofstudy
and (t.mark = minMark or t.mark = maxMark)
or for just the lowest mark per year:
select t.id, t.name, t.yearofstudy, t.mark
from t
inner join (
select
yearofstudy
, min(mark) as minMark
from t
group by yearofstudy
) as m
on t.yearofstudy = m.yearofstudy
and t.mark = minMark
You could write the query as follows:
SELECT t1.* from your_table t1
INNER JOIN (
SELECT yearofstudy, MIN(marks) as marks
FROM your_table GROUP BY yearofstudy
) t2
ON t1.yearofstudy = t2.yearofstudy
AND t1.marks = t2.marks
GROUP BY t1.yearofstudy
ORDER BY t1.yearofstudy, t1.id;
If all the MIN records for the yearofstudy are required, then you could simply remove GROUP BY t1.yearofstudy
Demo
I have two related tables:
(1) people contains names and image files.
(2) cities contains cities they have visited.
people
id name image
1 John NULL
2 Carrie 001.jpg
3 Desmond 002.jpg
4 Harry 003.jpg
5 Paul NULL
cities
id city people_id year_visited
1 Chicago 1 2000
2 Chicago 4 2000
3 Chicago 5 2001
4 Paris 1 2000
5 Paris 2 2002
6 Chicago 4 2002
7 Chicago 1 2001
8 London 1 2004
9 Sydney 5 2001
10 Sydney 1 2002
11 Rio 5 2002
12 London 5 2004
13 Sydney 5 2003
14 Sydney 5 2005
I would like to identify all people without an image, and the city they have visited the most. So the results I am looking for is:
name most_visited_city number_of_visits
John Chicago 2
Paul Sydney 3
I can group_concat the cities they have visited, but not drill down to the single city they visited the most.
All help gratefully appreciated.
The following gets people, cities, and the count:
select p.id, c.city, count(*) as cnt
from people p join
cities c
on p.id = c.people_id
where p.image is null
group by p.id, c.city;
Getting information about the most visited is tricky in MySQL. Here is one method that works if the data is not too large:
select id,
substring_index(group_concat(city order by cnt desc separator '|'), '|', 1) as most_visited_city,
max(cnt) as number_of_times_visited
from (select p.id, c.city, count(*) as cnt
from people p join
cities c
on p.id = c.people_id
where p.image is null
group by p.id, c.city
) pc
group by id;
This query should return the most visited city for each people_id in cities.
SELECT t1.people_id, t2.city, t2.visits
FROM (
SELECT people_id, MAX(visits) AS max_visits
FROM (
SELECT people_id, city, COUNT(*) AS visits
FROM cities
GROUP BY people_id, city) x
GROUP BY people_id) AS t1
JOIN (
SELECT people_id, city, COUNT(*) AS visits
FROM cities
GROUP BY people_id, city) AS t2
ON t1.people_id = t2.people_id AND t1.max_visits = t2.visits
The general structure is based on an answer in SQL Select only rows with Max Value on a Column, but instead of getting the max value of a column in the table, it's using the max value in the subquery that counts visits per city. Unfortunately, it results in an ugly query because you have to repeat that subquery, since MySQL doesn't have CTEs.
Then you can join it with people to get the person's name and filter out the ones with an image.
SELECT p.name, t2.city, t2.visits
FROM (
SELECT people_id, MAX(visits) AS max_visits
FROM (
SELECT people_id, city, COUNT(*) AS visits
GROUP BY people_id, city) x
GROUP BY people_id) AS t1
JOIN (
SELECT people_id, city, COUNT(*) AS visits
GROUP BY people_id, city) AS t2
ON t1.people_id = t2.people_id AND t1.max_visits = t2.max_visits
JOIN people AS p ON p.id = t1.people_id
WHERE p.image IS NULL
DEMO
This query
SELECT releases.id,releases.label_no_country,releases.date
FROM releases
INNER JOIN labels_user_has_recd luhr
ON luhr.label=releases.label_no_country
WHERE luhr.user='Si Quick'
GROUP BY releases.id
HAVING datediff(now(),releases.date) < 90
ORDER BY releases.date DESC
LIMIT 0,10
gives
id label_no_country date
605639 Church 2016-04-28
595303 Uncanny Valley 2016-04-21
605806 Dekmantel 2016-04-21
607276 Uncanny Valley 2016-04-21
604280 Delsin 2016-04-21
598653 Another Picture 2016-04-21
605016 Skylevel 2016-04-20
606342 Retreat 2016-04-14
599363 Frank Music 2016-04-12
599320 Spazio Disponibile 2016-04-08
I would like to not return any duplicates in column label_no_count (i.e. not Uncanny Valley twice.
I have tried using GROUP BY in the following query
SELECT releases.id,releases.label_no_country,releases.date
FROM releases
INNER JOIN labels_user_has_recd luhr
ON luhr.label=releases.label_no_country
WHERE luhr.user='Si Quick'
GROUP BY releases.label_no_country
HAVING datediff(now(),releases.date) < 90
ORDER BY releases.date DESC
LIMIT 0,10
but this only returns one result, rather than removing duplicates
id label_no_country date
599320 Spazio Disponibile 2016-04-08
Move the HAVING to WHERE condition like
WHERE datediff(now(),releases.date) < 90
Your query should be
SELECT releases.id,releases.label_no_country,releases.date
FROM releases
INNER JOIN labels_user_has_recd luhr
ON luhr.label=releases.label_no_country
WHERE luhr.user='Si Quick'
AND datediff(now(),releases.date) < 90
GROUP BY releases.label_no_country
ORDER BY releases.date DESC
LIMIT 0,10
I have a really complicated SQL question for a mySQL database.
I will first introduce all needed tables for this question:
User Table:
Id date_created
------------------------------
1 2015-09-19T14:18:07.000Z
2 2015-09-20T01:16:34.000Z
3 2015-09-21T15:10:21.000Z
…
Setting table:
Id User_id setting_key setting_value
----------------------------------------------
1 1 city 1
2 3 city 2
3 2 city 1
…
City names Table:
Id name
------------------
1 New York
2 Los Angeles
3 Boston
…
With a select-query I Would like to achieve this:
date New York Los Angeles Boston …
------------------------------------------------------
2015-09-19 1 0 0
2015-09-20 2 0 0
2015-09-21 2 1 0
…
For every date in certain range how many users has as setting New york, Los, Angeles....
The only thing I can achieve is this query:
select date(u.date_created), n.name, count(u.id)
from user u inner join setting s
on u.id = s.user_id
and setting_key = 'city'
inner join name n
on s.setting_value = n.id
where u.date_created > '2015-09-19T14:18:07.000Z'
group by 1, 2
but then I get this result:
date name count
-------------------------------
2015-09-19 New York 1
2015-09-19 Los Angeles 0
2015-09-19 Boston 0
2015-09-20 New York 1
2015-09-20 Los Angeles 0
2015-09-20 Boston 0
2015-09-21 New York 0
2015-09-21 Los Angeles 1
2015-09-21 Boston 0
…
It is not cummulative en there is row for each city instead of a column for each city. Does somebody know (the complicated) answer? If something is not clear just ask, In real live these are tables of 50.000 rows and I can't change the structure, I need this query for analytics purposes
If you know the names of the cities, just use conditional aggregation:
select date(u.date_created),
sum(name = 'New York') as NewYork,
sum(name = 'Los Angeles' as LosAngeles,
sum(name = 'Boston') as Boston
from user u inner join
setting s
on u.id = s.user_id and
setting_key = 'institution' inner join
education_niveau en
on s.setting_value = en.id
where u.date_created > '2015-09-19T14:18:07.000Z'
group by 1;
If you don't know the names of the cities or there are an unknown number, then you will need dynamic SQL -- that is, construct the SQL, prepare a statement, and then execute it.
EDIT:
It wasn't obvious at first that the question is about cumulative counts. For that, use variables:
select dte,
(#ny := #ny + NewYork) as NewYork,
(#la := #la + LosAngeles) as LosAngeles,
(#b := #b + Boston) as NewYork
from (select date(u.date_created) as dte,
sum(name = 'New York') as NewYork,
sum(name = 'Los Angeles' as LosAngeles,
sum(name = 'Boston') as Boston
from user u inner join
setting s
on u.id = s.user_id and
setting_key = 'institution' inner join
education_niveau en
on s.setting_value = en.id
where u.date_created > '2015-09-19T14:18:07.000Z'
group by 1
order by 1
) us cross join
(select #ny := 0, #la := 0, #b := 0) params
order by 1;
You want a pivot, which is not supported natively by mysql. However, this may work for you:
select date, group_concat(concat(name, '=', uid_count)) cities
from (
select date(u.date_created) date, en.name, count(u.id) uid_count
from user u
join setting s on u.id = s.user_id
join education_niveau en on s.setting_value = en.id
where u.date_created > '2015-09-19T14:18:07.000Z'
and setting_key = 'institution'
group by 1, 2) x
group by 1
which will produce a result like:
date Cities
------------------------------------------------------
2015-09-19 New York=1
2015-09-20 New York=2
2015-09-21 New York=2,Los Angeles=1
The main advantage with this approach is the range of cities returned is totally based on the data.