Running count based on field - mysql

I'd like to get a running count for each user with the query below
Does anyone know how I can do this? If I remove where user = 1 it gives me an overall running count due to the grouping.
I'd like to get running counts for user 1 through N. I'd rather not run the query for each user individually as there are a few million.
SET #runtot:=0;
SELECT q1.t, q1.user, q1.c, (#runtot := #runtot + q1.c) AS rt
FROM (
SELECT
time AS t,
user,
COUNT(distinct `post`) AS c
FROM
interactions
WHERE user = 1
GROUP BY
user,time
ORDER BY
user
) AS q1

You can use this query:
SET #runtot:=0;
SET #last_user:=NULL;
SELECT
q1.t,
q1.user,
q1.c,
CASE WHEN #last_user=q1.user
THEN #runtot := #runtot + q1.c
ELSE #runtot:=q1.c END AS rt,
#last_user:=q1.user
FROM (
...
) AS q1
This query will keep last user into the #last_user variable, and whenever the user changes it will start the count again.

Related

How to get results from two sql query results

I"m using SET #runtot:=0 at the top of my SQL code and it gets 2 query results:
The first one is:
MySQL returned an empty result set (i.e. zero rows). (Query took
0.0002 seconds.)
The second is:
Showing rows 0 - 7 (8 total, Query took 0.0058 seconds.)
how can i get the results of the second query only?
here is my SQL code:
SET #runtot:=0;
SELECT
fname,
lname,
guests,
phone
FROM (
(SELECT *, 0 AS rt FROM guests_table WHERE status = 2)
UNION
(SELECT *, (#runtot := #runtot + rsvp.guests) AS rt
FROM
(SELECT *
FROM guests_table
WHERE status != 2
) AS rsvp
WHERE #runtot + rsvp.guests <= 4)
)rsvp
ORDER BY rsvp.id ASC
You can set the parameters in the query:
SELECT fname, lname, guests, phone
FROM ((SELECT *, 0 AS rt FROM guests_table WHERE status = 2)
UNION
(SELECT *, (#runtot := #runtot + rsvp.guests) AS rt
FROM (SELECT *
FROM guests_table
WHERE status != 2
) AS rsvp
WHERE #runtot + rsvp.guests <= 4)
) rsvp CROSS JOIN
(SELECT #runtot := 0) params
ORDER BY rsvp.id ASC;
Note that the use of variables in SELECT queries like this has been deprecated. In MySQL 8+, you should be using window functions.
In addition, the "running sum" is reading the rows in an arbitrary order. There is no guarantee that the result will be in the same order as the results.
If you want further help with the query, ask a new question. Provide sample data, desired results, and a clear explanation of the logic.

SQL query to select last X entries for a certain non-primary field

I'm having difficulties setting up a slightly more advanced SQL query.
What I'm trying to do is to select the last 24 entries for every zr_miner_id, but I keep getting SQL timeouts (the table has around 40000 entries so far).
So let's say there's 200 entries for zr_miner_id 1 and 200 for zr_miner_id 2, I'd end up with 48 results.
So far, I've come up with the query below.
What this is supposed to do is to select each result in zec_results that has less than 24 newer entries with the same zr_miner_id.
I couldn't think of any better way to perform this task, but then again, I'm not that far advanced at SQL yet.
SELECT results_a.*
FROM zec_results results_a
WHERE (
SELECT COUNT(results_b.zr_id)
FROM zec_results AS results_b
WHERE results_b.zr_miner_id = results_a.zr_miner_id
AND results_b.zr_id >= results_a.zr_id
) <= 24
Use variables!
SELECT r.*
FROM (SELECT r.*,
(#rn := if(#m = r.zr_miner_id, #rn + 1,
if(#m := r.zr_miner_id, 1, 1)
)
) as rn
FROM zec_results r CROSS JOIN
(SELECT #m := -1, #rn := 0) params
ORDER BY r.zr_miner_id, r.zr_id DESC
) r
WHERE rn <= 24 ;
If you want to put the query into a view, then the above will not work. Performance on your approach might improve with an index on (zr_miner_id, zr_id).

Mysql recursive substracting and multiplying values

Couldn't really explain my problem with words, but with an example I can show it clearly:
I have a table like this:
id num val
0 3 10
1 5 12
2 7 12
3 11 15
And I want to go through all the rows, and calculate the increase of the "num", and multiply that difference with the "val" value. And when I calculated all of these, I want to add these results together.
This is the mathematical equation, that I want to run on the table:
Result = (3-0)*10 + (5-3)*12 + (7-5)*12 + (11-7)*15
138 = Result
Thank you.
You can do with mysql variables, but you will still get one record for each entry.
select
#lastTotal := #lastTotal + ( (yt.num - #lastNum) * yt.val ) thisLineTotal,
#lastNum := yt.num as saveForNextRow,
yt.id
from
yourTable yt,
( select #lastTotal := 0,
#lastNum := 0 ) sqlvars
order by
id
This SHOULD give you what you want to confirm the calculations to each record basis.
Now, to get the one record and one column result, you can wrap it such as
select
pq.thisLineTotal
from
(above entire query ) as pq
order by
pq.id DESC
limit 1
Assuming the IDs are consecutive as your sample data suggests, just join the table to itself:
select sum((t1.num-ifnull(t2.num,0))*t1.val) YourValue
from YourTable t1
left join YourTable t2
on t2.id = t1.id - 1;
http://www.sqlfiddle.com/#!2/40b9f/12
This will give you the total. Make sure to order in the order you wish - I have ordered by id
SET #runtot:=0;
SET #prevval:=0;
select max(rt) as total FROM (
SELECT
q.val,
q.num,
(#runtot := #runtot + (q.num- #prevval) * q.val) AS rt,
(#prevval := q.num) AS pv
FROM thetable q
ORDER by ID) tot
If you want to see the details of the calculation, leave out the outer select as so:
SET #runtot:=0;
SET #prevval:=0;
SELECT
q.val,
q.num,
(#runtot := #runtot + (q.num- #prevval) * q.val) AS rt,
(#prevval := q.num) AS pv
FROM thetable q
ORDER by ID
If it is possible to have negative numbers for your column values, using max(rt) won't work for the total. You should then use:
SET #runtot:=0;
SET #prevval:=0;
select #runtot as total FROM (
SELECT
q.val,
q.num,
(#runtot := #runtot + (q.num- #prevval) * q.val) AS rt,
(#prevval := q.num) AS pv
FROM thetable q
ORDER by ID) tot LIMIT 1

MySQL group by time buckets

I have a activity log with the following schema:
visitor_id, metadata, timestamp
The first field is the visitors id, the second some metadata for a given activity and the last a unix timestamp from when the activity occurred.
Now, i want to identify individual sessions from this log. That is; i want to group all rows for each visitor where the timestamp is no longer then x seconds apart (eg. 20*60 for 20 minutes) from either the previous or following row by the same visitor.
How can that be done?
You can create something like custom groups like this:
SELECT
t.visitor_id,
MIN(t.timestamp),
MAX(t.timestamp)
FROM (
SELECT
IF(#lt < l.`timestamp` - 60*20 OR l.visitor_id != #lv, #g := #g + 1, #g) as g,
#lv := l.visitor_id,
#lt := l.`timestamp`,
l.*
FROM your_log l
JOIN (SELECT #g := 1, #lt = 0, #lv = NULL) as init
ORDER BY l.visitor_id, l.`timestamp`
) as t
GROUP BY t.visitor_id, g

Using MYSQL conditional statements and variables within a query

Hi just cant seem to construct the MYSQL query Im after.
Say I have a result of two columns: 1) browser name and 2) browser count.
Where it gets complicated is I want once 90% of the total count has been reached to rename all other browsers as others and mark the left over percentage accordingly.
I know I can get the total count as a variable before I begin the main statement:
SELECT #total := COUNT(id) FROM browser_table WHERE start LIKE "2010%";
Then I can group the results by browser:
SELECT browser, COUNT(id) AS visits
FROM browser_table
WHERE start LIKE "2010%"
GROUP BY browser
I know I need to whack in a case statement (and a counter variable) to sort the columns but not sure of how to implement the into the above query:
CASE
WHEN counter >= 0.9* #total THEN 'other'
ELSE browser
END AS browser;
Hope that makes sense? Thanks for your time....
Here's one approach...
You can calculate a running total based on this answer. Example:
SET #rt := 0;
SELECT
browser,
visits,
(#rt := #rt + visits) AS running_total
FROM
(
SELECT
browser,
COUNT(id) AS visits
FROM
browser_table
WHERE
start LIKE '2010%'
GROUP BY
browser
ORDER BY
visits DESC
) AS sq
;
Once you have that in place, you can build on that to create an 'Other' category:
SET #threshold := (SELECT COUNT(id) FROM browser_table WHERE start LIKE '2010%') * 0.90;
SET #rt := 0;
SELECT
browser,
SUM(visits) AS total_visits
FROM
(
SELECT
IF (#rt < #threshold, browser, 'Other') AS browser,
visits,
(#rt := #rt + visits) AS running_total
FROM
(
SELECT
browser,
COUNT(id) AS visits
FROM
browser_table
WHERE
start LIKE '2010%'
GROUP BY
browser
) AS sq1
ORDER BY
visits DESC
) AS sq2
GROUP BY
browser
ORDER BY
total_visits DESC
;