How to use SQL to count events in the first week - mysql

I'm trying to write a SQL query, which says how many logins each user made in their first week.
Assume, for the purpose of this question, that I have a table with at least user_id and login_date. I'm trying to produce an output table with user_id and num_logins_first_week

Use aggregation to get the first date for each user. Then join in the logins and aggregate:
select t.user_id, count(*) as num_logins_first_week
from t join
(select user_id, min(login_date) as first_login_date
from t
group by user_id
) tt
on tt.user_id = t.user_id and
t.login_date >= tt.first_login_date and
t.login_date < tt.first_login_date + interval 7 day
group by t.user_id;

Related

When will recursive query stop in this case?

Given this table description.
I have written a query to find Users who logged in for 5 or more consecutive days.
WITH RECURSIVE
rec_t AS
(SELECT id, login_date, 1 AS days FROM Logins
UNION ALL
SELECT l.id, l.login_date, rec_t.days+1 FROM rec_t
INNER JOIN Logins l
ON rec_t.id = l.id AND DATE_ADD(rec_t.login_date, INTERVAL 1 DAY) = l.login_date
)
SELECT * FROM Accounts
WHERE id IN
(SELECT DISTINCT id FROM rec_t WHERE days = 5)
ORDER BY id
Code Explanation :
For every id and login date, match the CTE table with the same id and +1 login_date.
the "days" column just increments +1 everytime the same user_id appears.
The Problem:
Although the query works fine, I just don't know where am I asking the query to stop the recursion. There isn't a "where" in RECURSIVE CTE definition. However, the inner join might help to dictate that there are no more login_date to match on. But I am uncertain that is the case.

MySQL query with GROUP BY and ORDER BY timestamp DESC

I am saving the history of Facebook likes for a page, identified by user_id.
Now from this table, I need to get a set representing the user_id's and their latest number of likes, based on the most recent timestamp.
I started off with this:
SELECT *
FROM facebook_log
GROUP BY user_id
ORDER BY timestamp DESC;
But that does not do what I want because it returns the first records with the lowest timestamps.
I read something online about GROUP returning the very first records from the table.
I also understood something about JOIN the table with itself, but that doesn't work either, or I did something wrong.
If you just need the user_id and the timestamp, you can just do
select f.user_id, max(f.timestamp)
from facebook_log
group by user_id;
if you need all the data from the table, you can do
select f.*
from facebook_log f
inner join (select max(timestamp) mt, user_id
from facebook_log
group by user_id) m
on m.user_id = f.user_id and m.mt = f.timestamp
You can also get the latest number of likes by using this MySQL trick:
select f.user_id, max(f.timestamp),
substring_index(group_concat(f.numlikes order by f.timestamp desc), ',', 1) as LatestLikes
from facebook_log f
group by f.user_id;

Query that returns duplicate record frequencies

I have an "updates" table that can contain duplicate descriptions, and I would like to return the duplicates along with their count, so I created this query:
SELECT description, count(description) AS count
FROM updates INNER JOIN participations ON participations.update_id = updates.id
INNER JOIN customer ON customer.id = participations.customer_id
INNER JOIN garages ON garages.id = customer.garage_id
WHERE (updates.created_at >= DATE_SUB(CURDATE(), INTERVAL 6 MONTH))
AND garages.`id` = 1
GROUP BY description
ORDER BY count desc
LIMIT 10
The counts returned were not what I was expecting. I believe the reason why is because many customers can share an update, so I am getting duplicates because of the actual duplicates in the table, and because the same update record is being returned multiple times. How can I fix the query so that it only counts the actual duplicate description fields in the update table. Thanks
You might rewrite your query to use EXISTS because you need customers just to get to garage :-)
SELECT description, count(description) AS count
FROM updates
WHERE (updates.created_at >= DATE_SUB(CURDATE(), INTERVAL 6 MONTH))
AND EXISTS (select null from participations INNER JOIN customer ON customer.id = participations.customer_id WHERE participations.update_id = updates.id AND customer.garage_id = 1)
GROUP BY description
ORDER BY count desc
LIMIT 10

get the average time for time from subscription until payment

I have two tables. The first is subscribers. Subscribers are also appointed to a category. The second table is payments that the subscribers made. I want to know what the average time is between the time of subscription and the FIRST payment of a subscriber (the can make multiple).
Here is a piece of SQL, but it doesn't do what I want just yet - although I have the feeling I'm close ;)
SELECT category,
AVG(TIMESTAMPDIFF(HOUR, subs.timestamp, MIN(payments.timestamp)))
FROM subs
JOIN payments ON (payments.user_id = subs.user_id)
GROUP BY category
Now I get "Invalid use of group function" - because of the MIN function, so that ain't right. What do I have to do now? Thanks in advance!
SELECT category,
AVG(TIMESTAMPDIFF(HOUR, subs.timestamp, p.timestamp))
FROM subs
JOIN ( SELECT user_id
, min(timestamp) timestamp
FROM payments
GROUP BY user_id
) p
ON p.user_id = subs.user_id
GROUP BY category
If you needed to update another table with the results of this query, you could do something like this (not tested, so there may be syntax errors but hopefully you get the idea). I assume that another_table has category and avg_hrs_spent columns.
UPDATE another_table
SET avg_hrs_spent =
(
SELECT a.avg_hrs_spent FROM
(
(SELECT category,
AVG(TIMESTAMPDIFF(HOUR, subs.timestamp, p.timestamp)) avg_hrs_spent
FROM subs
JOIN ( SELECT user_id
, min(timestamp) timestamp
FROM payments
GROUP BY user_id
) p
ON p.user_id = subs.user_id
GROUP BY category) a
)
WHERE a.category = another_table.category
)

count total records after groupBy select

I have a mysql select query that has a groupBy.
I want to count all the records after the group by statement.
Is there a way for this directly from mysql ?
thanks.
If the only thing you need is the count after grouping, and you don't want to use 2 separate queries to find the answer. You can do it with a sub query like so...
select count(*) as `count`
from (
select 0 as `doesn't matter`
from `your_table` yt
group by yt.groupfield
) sq
Note: You have to actually select something in the sub query, but what you select doesn't matter
Note: All temporary tables have to have a named alias, hence the "sq" at the end
You can use FOUND_ROWS():
SELECT <your_complicated_query>;
SELECT FOUND_ROWS();
It's really intended for use with LIMIT, telling you how many rows would have been returned without the LIMIT, but it seems to work just fine for queries that don't use LIMIT.
see this query for examples:
This query is used to find the available rooms record for a hotel, just check this
SELECT a.type_id, a.type_name, a.no_of_rooms,
(SELECT SUM(booked_rooms) FROM reservation
WHERE room_type = a.type_id
AND start_date >= '2010-04-12'
AND end_date <= '2010-04-15') AS booked_rooms,
(a.no_of_rooms - (SELECT SUM(booked_rooms)
FROM reservation
WHERE room_type = a.type_id
AND start_date >= '2010-04-12'
AND end_date <= '2010-04-15')) AS freerooms
FROM room_type AS a
LEFT JOIN reservation AS b
ON a.type_id = b.room_type
GROUP BY a.type_id ORDER BY a.type_id