I have a table with site visits with the following columns:
timestamp
host
url
I would like to see the last few (say 200) visits but at the same time group visits of the same host together (to see the sequence of pages he/she visits).
If I do:
... SORT BY timestamp DESC, host
I get hosts mixed up if several visitors are online at the same time
If I do:
... SORT BY host, timestamp DESC
I do not get the latest visits (just the latest visits from each host)
I would like to see e.g.
9:01 | a.com | /index
9:05 | a.com | /interesting
9:07 | a.com | /contact
9:02 | b.com | /index
9:03 | b.com | /product-a
9:08 | b.com | /thanks-for-buying
Is that possible in Mysql or should I further process the result in php?
Try this::
Select *, MAX(timestamp_col) as lastVisit from site_table
GROUP BY HOSTS order by lastVisit desc
You can't do ORDER BY followed by LIMIT and then another ORDER BY, so you have to use a sub query:
SELECT * FROM (SELECT *
FROM visits
ORDER BY timestamp DESC
LIMIT 200
) visits2
ORDER BY host
You have to limit the result if you want the last 200
SORT BY timestamp DESC, host LIMIT 0, 200
And if you dont the same visitor to show up again , use
SELECT DISTINCT visitor FROM ....
I think it is not possible make normal in one query. You can try this:
SELECT *
FROM table AS t1
WHERE t1.timestamp_col >= (SELECT MIN(tstamp)
FROM (SELECT t2.timestamp_col
FROM tables AS t2
WHERE t2.host = t1.host
ORDER BY timestamp_col DESC
LIMIT 200
)
)
I don't test this crazy code... But I hope it give you way :)
The answers above pointed my in the right direction, thanks. This one works. The LIMIT 1000 is to reduce the query from almost 3 minutes to 7 seconds (40000 records).
SELECT v1.stamp, v1.host FROM visits AS v1
LEFT JOIN (SELECT MIN(date) AS firstVisit, host
FROM visitor AS v2
GROUP BY v2.host
ORDER BY firstVisit DESC
LIMIT 1000) AS j
ON v1.host=j.host
ORDER BY firstVisit DESC, v1.host, v1.date DESC
LIMIT 100;
Related
I have been trying to find a way to do this but I can't seem to figure out how.
The following table is the one I am trying to "clean up".
-------------
| Messages |
-------------
| ID |
| user_id |
| msg |
| timestamp |
-------------
Basically I want to remove all messages except for the latest 10 per user_id.
I really have no idea how to go about this.
Any suggestions would be useful.
See Using LIMIT within GROUP BY to get N results per group? for how to write a query that finds the newest 10 rows for each user_id. Then you can write a query that joins with that as a subquery, and deletes rows that aren't in it.
DELETE t1.*
FROM YourTable AS t1
LEFT JOIN (SELECT ...) AS t2
ON t1.id = t2.id
WHERE t2.id IS NULL
Replace (SELECT ...) with a query you found in the other question.
You need repeat this for every user.
DELETE FROM Messages where user_id='xyz' and ID NOT IN
(SELECT * FROM
(SELECT ID FROM Messages where user_id='xyz' ORDER BY timestamp DESC LIMIT 10)
AS TOP10)
try something like this -
delete from messages where ID = (SELECT ID FROM messages
ORDER BY timestamp DESC
LIMIT 10)
I am not sure if this will work, but might give you an Idea of how it can be done.
I hope this helps.
I have a query which actually have a sorting using order by clause. i have a table like following...
user_id user_name user_age user_state user_points
1 Rakul 30 CA 56
2 Naydee 29 NY 144
3 Jeet 40 NJ 43
.....
i have following query...
select * from users where user_state = 'NY' order by user_points desc limit 50;
This gives me the list of 50 people with most points. I wanted to give least preference to few people who's id's were known. Incase if i do not have enough 50 records then those id's should come in the last in the list. I do not want the users 2 and 3 to come on top of the list even though they have higher points... those people should come on the last of the list from the query. Is there any way to push specific records to last on result set irrespective of query sorting ?
If you want to move specific records (like user_id = 2 and 3) down to the list; Then you can run below Query:
mysql> select *,IF(user_id=2 or user_id=3,0,1) as list_order from users where user_state = 'NY' order by list_order desc, user_points desc limit 50;
select * from (
select *
from users
where user_state = 'NY'
-- this order by ensures that 2 and 3 are included
order by case when user_id in (2,3) then 1 else 2 end, user_points desc
limit 50
) as top48plus2n3
-- this order by ensures that 2 and 3 are last
order by case when user_id in (2,3) then 2 else 1 end, user_points desc
Edit: changed id by user_id and corrected outside order by (sorry about that)
On the inner select:
By using this case calculation, what you do is ensuring that records with ids equal to 2 and 3 are "important" (firstly ordered in the order by). Those receive 1 while the others receive 2 as order value, only after that points are relevant.
On the outer select:
Records with ids 2 and 3 recieve 2 as order value, while the rest recieve 1. So they go last irrespective of its "default"
Here you have a reduced fiddle http://sqlfiddle.com/#!9/377c1/1
My table is:
+----visits----+
| id |
| client_ip |
| date |
| type |
+--------------+
It stores all site user visits. Now i need to make a graph by getting data from this table, my query is:
SELECT COUNT(*) as hit_counts, date FROM visits GROUP BY date ORDER BY date ASC LIMIT 25
But the idea is that each time i refresh a page on my site, i get a new row inserted in table, and mysql counts 25 records(but i need to limit my query at 25 days(1 day can have 100+ visits), not only 25 records).
Try this:
SELECT temp_table.* FROM
(SELECT COUNT(*) as hit_counts, date
FROM visits
GROUP BY date) as temp_table
ORDER BY temp_table.date ASC
LIMIT 25
use DESC for the last 25 days.
I have a table with: id, client, domain and bytes. I have a query that gets the top 3 users either by client:
SELECT client FROM log
GROUP BY 1
ORDER BY SUM(bytes) DESC
LIMIT 3
or by domain
SELECT domain FROM log
GROUP BY 1
ORDER BY SUM(bytes) DESC
LIMIT 3
Is there a way in MySQL to get this two mixed without a stored procedure? For example, get the top 3 clients, each client row followed by the top 3 domains used BY THAT CLIENT in a single query execution?
192.168.1.1
google.com
facebook.com
twitter.com
192.168.1.2
facebook.com
twitter.com
...
...
For example, to get the top 3 domain usage from client 192.168.1.1:
SELECT domain FROM log
WHERE client = '192.168.1.1'
GROUP BY 1
ORDER BY SUM(bytes) DESC
LIMIT 3
So for each row in query #1, somehow this query should be executed. So far I got to show a concatenated list of top domains for each client, sadly not related to the same client because I can't access outer_client in subquery:
SELECT client AS outer_client, top_domain
FROM log
JOIN (
SELECT GROUP_CONCAT(t.domain) AS top_domain
FROM (
SELECT domain
FROM log
WHERE client = outer_client
GROUP BY 1
ORDER BY SUM(bytes)
LIMIT 5
) t
) k
GROUP BY client
ORDER BY SUM(bytes)
LIMIT 5;
One solution:
http://sqlfiddle.com/#!2/cc1b1/2/0
SELECT client
, (SELECT domain
FROM log
WHERE client=top_clients.client
GROUP BY client, domain
ORDER BY SUM(bytes) DESC
LIMIT 1) domain1
, (SELECT domain
FROM log
WHERE client=top_clients.client
GROUP BY client, domain
ORDER BY SUM(bytes) DESC
LIMIT 1 OFFSET 1) domain2
, (SELECT domain
FROM log
WHERE client=top_clients.client
GROUP BY client, domain
ORDER BY SUM(bytes) DESC
LIMIT 1 OFFSET 2) domain3
FROM (SELECT client FROM log GROUP BY client ORDER BY SUM(bytes) DESC LIMIT 3) top_clients;
My output:
+-------------+--------------+--------------+-------------+
| client | domain1 | domain2 | domain3 |
+-------------+--------------+--------------+-------------+
| 192.168.1.1 | google.com | facebook.com | twitter.com |
| 192.168.1.2 | facebook.com | twitter.com | NULL |
+-------------+--------------+--------------+-------------+
Assuming you have access to PHPMySQL, and your server allows it, what you're looking for is a VIEW.
You write your SQL to get your data set. And rather than saving it in a temporary table (which would make it static), you save it in a VIEW. Once you have that view, you can always use it the same as if it were a table. In fact, it actually SHOWS the data set in a table format as if that's exactly what it was.
You can run queries against it, with JOINS... Anything you would do with a table.
And it's actual live data.
Here it is:
select client,
substring_index(group_concat(domain order by sumbytes desc), ',', 5) as top5domains
from (
select client, domain, sum(bytes) as sumbytes
from log
group by client, domain
) cd
group by client
order by sum(sumbytes) desc
limit 5;
Courtesy of #Gordon Linoff here: MySQL GROUP_CONCAT from subquery
According to your question, you are ordering by the same thing in each example. If that's the case, the row you return should have both client and domain already in it. So would this solve your problem?
SELECT client, domain FROM log
GROUP BY 1
ORDER BY SUM(bytes) DESC
LIMIT 3
I have the following table (user_record) with millions of rows like this:
no uid s
================
1 a 999
2 b 899
3 c 1234
4 a 1322
5 b 933
-----------------
The uid can be duplicate .What I need is to show the top ten records(need inclued uid and s) with no duplicate uid order by s (desc). I can do this by two steps in the following SQL statements:
SELECT distinct(uid) FROM user_record ORDER BY s DESC LIMIT 10
SELECT uid,s FROM user_record WHERE uid IN(Just Results)
I just wana know is there a bit more efficient way in one statement?
Any help is greatly appreciated.
ps:I also have following the SQL statement:
select * from(select uid,s from user_record order by s desc) as tb group by tb.uid order by tb.s desc limit 10
but it's slow
The simpliest would be by using MAX() to get the highest s for every uid and sorted it based on the highest s.
SELECT uid, MAX(s) max_s
FROM TableName
GROUP BY uid
ORDER BY max_s DESC
LIMIT 10
SQLFiddle Demo
The disadvantage of the query above is that it doesn't handles duplicates if for instance there are multiple uid that have the same s and turn out to be the highest value. If you want to get the highest value s with duplicate, you can do by calculating it on the subquery and joining the result on the original table.
SELECT a.*
FROM tableName a
INNER JOIN
(
SELECT DISTINCT s
FROM TableName
ORDER BY s DESC
LIMIT 10
) b ON a.s = b.s
ORDER BY s DESC