Retention of users on an Ott platform - mysql

I have table called user_info
It has two columns:
User_id
Date
How do I get to the table like the one mentioned below:
----------------------------------------------------------------
Date |total_number_of_users | D2 |D5 | D7 | D14|
--------------------------------------------------------------
2020-07-01 1000 700 500 200 150
2020-07-02 400 300 250 200 100
For example consider the first row in the table I am trying to achieve:
total_number_of_users = Total number of users who have visited the site on 2020-07- 01
D2=Out of total users who visited the site on 2020-07-01, visited on 2020-07-2
D7=Out of total users who visited the site on 2020-07-01, visited on 2020-07-7
I have tried the following, how do I get the exact the solution:
SELECT user_id, week(login_date) AS login_week
FROM user_info
GROUP BY user_id,week(login_date);
SELECT user_id, min(week(login_date)) AS first_week
FROM user_info
GROUP BY user_id;
select a.user_id,a.login_week,b.first_week as first_week from
(SELECT
user_id,
week(login_date) AS login_week
FROM user_info
GROUP BY user_id,week(login_date)) a,
(SELECT
user_id,
min(week(login_date)) AS first_week
FROM user_info
GROUP BY user_id) b
where a.user_id=b.user_id;

This seems painful, but you can use a self-join and aggregation:
select t.date,
sum( t2.date = t.date) as total_number_of_users,
sum( t2.date = t.date + interval 1 day ) as d2,
sum( t2.date = t.date + interval 4 day ) as d5,
sum( t2.date = t.date + interval 6 day ) as d7,
sum( t2.date = t.date + interval 13 day ) as d14
from (select distinct date, user_id
from t
) t1 left join
(select distinct date, user_id
from t
) t2
on t1.user_id = t2.user_id and
t2.date in (t1.date, t1.date + interval 1 day, t1.date + interval 4 day, t1.day + interval 6 day, t1.day + interval 13 day)
group by t.date;

Related

Calculate Ratio of two different SQL queries result that return numbers

I have Query 1
SELECT COUNT(DISTINCT user_id) total_daily_active_user_group_month FROM (SELECT user_id , MONTHNAME(time) mon , COUNT(*) cnt FROM ACTIVITIES
WHERE MONTH(time) = MONTH(NOW() - INTERVAL 1 MONTH) GROUP by user_id, MONTH(time) ) as x
Returns 18
Query 2
SELECT COUNT(DISTINCT user_id) total_daily_active_user_group_month FROM (SELECT user_id , MONTHNAME(time) mon , COUNT(*) cnt FROM ACTIVITIES
WHERE MONTH(time) = MONTH(NOW() - INTERVAL 1 MONTH) GROUP by user_id, MONTH(time) having cnt=31) as x
Return 6
I want the ratio of query 1 and two. Means
18/6 . I am using MySQL
If you use both queries as CTEs, then it becomes relatively simple:
WITH q1
AS (SELECT Count(DISTINCT user_id) total_daily_active_user_group_month
FROM (SELECT user_id,
Monthname(TIME) mon,
Count(*) cnt
FROM activities
WHERE Month(TIME) = Month(Now() - interval 1 month)
GROUP BY user_id,
Month(TIME))),
q2
AS (SELECT Count(DISTINCT user_id) total_daily_active_user_group_month
FROM (SELECT user_id,
Monthname(TIME) mon,
Count(*) cnt
FROM activities
WHERE Month(TIME) = Month(Now() - interval 1 month)
GROUP BY user_id,
Month(TIME)
HAVING cnt = 31))
SELECT q1.total_daily_active_user_group_month /
q2.total_daily_active_user_group_month
AS result
FROM dual;
You commented that you got an error pointing to the WITH keyword; switch to two subqueries, then; simplified:
select a.value / b.value as result
from (select count(distinct user_id) value
from ... your 1st query goes here
) a,
(select count(distinct user_id) value
from ... your 2nd query goes here
) b;

How do I create multiple views in the same query in SQL and then join them?

This is the query that I am using.
I need to join the three views to calculate the monthly total revenue.
How should I proceed?
With Txn as(
Select DATE_FORMAT(DATE_ADD(createdAt, interval 330 MINUTE), '%y-%m') as Month, Sum(netPrice/100) as TransactionRevenue from transactions
group by Month)
With Leaves as(
Select DATE_FORMAT(DATE_ADD(createdAt, interval -1 MONTH), '%y-%m') as Month, sum(amount/100) as LeaveRevenue from driverPaymentTransactions
group by Month)
With Sxn as(
Select DATE_FORMAT(DATE_ADD(createdAt, interval 330 MINUTE ), '%y-%m') as Month, sum(amount/100) as SubscribedRevenue from subscribedDriversDailyRevenues
group by MONTH)
Select * from Txn t
join Leaves l on t.Month = l.month
join Sxn s on t.month = s.month
With Txn as(
Select DATE_FORMAT(DATE_ADD(createdAt, interval 330 MINUTE), '%y-%m') as Month, Sum(netPrice/100) as TransactionRevenue from transactions
group by Month),
Leaves as(
Select DATE_FORMAT(DATE_ADD(createdAt, interval -1 MONTH), '%y-%m') as Month, sum(amount/100) as LeaveRevenue from driverPaymentTransactions
group by Month),
Sxn as(
Select DATE_FORMAT(DATE_ADD(createdAt, interval 330 MINUTE ), '%y-%m') as Month, sum(amount/100) as SubscribedRevenue from subscribedDriversDailyRevenues
group by MONTH)
Select * from Txn t
join Leaves l on t.Month = l.month
join Sxn s on t.month = s.month
You need to "join" the subqueries
CREATE VIEw myview
AS (With Txn as(
Select DATE_FORMAT(DATE_ADD(createdAt, interval 330 MINUTE), '%y-%m') as Month, Sum(netPrice/100) as TransactionRevenue from transactions
group by Month)
, Leaves as(
Select DATE_FORMAT(DATE_ADD(createdAt, interval -1 MONTH), '%y-%m') as Month, sum(amount/100) as LeaveRevenue from driverPaymentTransactions
group by Month)
, Sxn as(
Select DATE_FORMAT(DATE_ADD(createdAt, interval 330 MINUTE ), '%y-%m') as Month, sum(amount/100) as SubscribedRevenue from subscribedDriversDailyRevenues
group by MONTH)
Select * from Txn t
join Leaves l on t.Month = l.month
join Sxn s on t.month = s.month)
Do not join when you need to "pull" some different measures to the common attribute. Use union all, where you do not need to care about the most complete source of group values:
create table t1 as
select 1 as id, 10 as val union all
select 1, 20 union all
select 2, 30 union all
select 3, 49
create table t2 as
select 1 as id, 10 as val union all
select 3, 20 union all
select 3, 30 union all
select 5, 49
create table t3 as
select 4 as id, 10 as val union all
select 6, 20 union all
select 2, 30 union all
select 3, 49
with u as (
select
id
, val as t1_val
, cast(null as decimal) as t2_val
, cast(null as decimal) as t3_val
from t1
union all
select
id
, null as t1_val
, val as t2_val
, null as t3_val
from t2
union all
select
id
, null as t1_val
, null as t2_val
, val as t3_val
from t3
)
select
id
, sum(t1_val) as t1_val
, sum(t2_val) as t2_val
, sum(t3_val) as t3_val
from u
group by id
id | t1_val | t2_val | t3_val
-: | -----: | -----: | -----:
1 | 30 | 10 | null
2 | 30 | null | 30
3 | 49 | 50 | 49
5 | null | 49 | null
4 | null | null | 10
6 | null | null | 20
db<>fiddle here

How to change format of the MySQL result?

I have a complex mysql query language, including several sub queries and my final result is as below. There is something that I am dealing with it and I can't solve it and this is a way result is being presented. I am wondering to know how can i change the structure of the result in a way that the result is being presented only in one row and I don't want to see NULL fields. I mean something like below
This is mysql query
select count(*) as userRetentionSameDay, null as 'userRetentionDiffDay' from (SELECT date(`timestamp`), `user_xmpp_login`
FROM table1
WHERE DATE(`timestamp` ) = CURDATE() - INTERVAL 1 DAY) as res1
right join (select date(ts), user
from table2
WHERE DATE(ts ) = CURDATE() - INTERVAL 1 DAY
and product_id REGEXP ("^(europe+$" )) as lej1
on lej1.user = res1.`user_xmpp_login`
where res1.`user_xmpp_login` IS not NULL
union all
select null as 'userRetentionSameDay', count(*) as userRetentionDiffDay from (SELECT date(`timestamp`), `user_xmpp_login`
FROM table1
WHERE DATE(`timestamp` ) = CURDATE() - INTERVAL 1 DAY) as res1
right join (select date(ts), user
from table2
WHERE DATE(ts ) = CURDATE() - INTERVAL 1 DAY
and product_id REGEXP ("^(europe+$" )) as lej2
on lej2.user = res1.`user_xmpp_login`
where res1.`user_xmpp_login` IS NULL;
What are the recommended solutions to doing that?
try this.
SELECT A.userRetentionSameDay,B.userRetentionDiffDay FROM (
SELECT COUNT() AS userRetentionSameDay FROM
(
SELECT DATE(timestamp), user_xmpp_login
FROM table1
WHERE DATE(timestamp ) = CURDATE() - INTERVAL 1 DAY) AS res1
RIGHT JOIN (SELECT DATE(ts), USER
FROM table2
WHERE DATE(ts ) = CURDATE() - INTERVAL 1 DAY
AND product_id REGEXP ("^(europe+$" )) AS lej1
ON lej1.user = res1.user_xmpp_login
WHERE res1.user_xmpp_login IS NOT NULL
) A,
(
SELECT COUNT() AS userRetentionDiffDay FROM (
SELECT DATE(timestamp), user_xmpp_login
FROM table1
WHERE DATE(timestamp ) = CURDATE() - INTERVAL 1 DAY
) AS res1
RIGHT JOIN (SELECT DATE(ts), USER
FROM table2
WHERE DATE(ts ) = CURDATE() - INTERVAL 1 DAY
AND product_id REGEXP ("^(europe+$" )
) AS lej2
ON lej2.user = res1.user_xmpp_login
WHERE res1.user_xmpp_login IS NULL
) B;

how to find duplicate records in a table within a predefined time period in sql

For example, i have following table
Mobile number Timestamp
123456 17-09-2015 11:30
455677 17-09-2015 12:15
123456 17-09-2015 12:25
453377 17-09-2015 13:15
If now is 11:30, I want to scan my table and find rows with the same numbers within the past 1 hour.
That's my SQL statement:
select a.number, a.time
from mytable a inner join
(select number, time
from mytable b
where time>=now()-Interval 1 hour and time<=now ()
group by number
Having count(*) > 1
) b
on a.number = b.number and a.time = b.time
I want to find duplicate rown with the same numbers happening within 1 hour. I should output the number and timestamp.
How about just using exists?
select t.*
from mytable t
where t.time >= now() - Interval 1 hour and
t.time <= now() and
exists (select 1
from mytable t2
where t2.number = t.number and
t2.time >= now() - Interval 1 hour and
t2.time <= now () and
t2.time <> t.time
);
However, I suspect that the problem with your query is the join to time. Just remove the time from the subquery and the on clause and you will get all numbers. Alternatively, use group by:
select t.number, group_concat(time)
from mytable t
where t.time >= now() - Interval 1 hour and
t.time <= now()
group by t.number
having count(*) > 1;

mysql multiple tables select last 7 days

I am having 3 tables, containing some records which have a date and a numeric value (the tables can't be merged). I want to make up a bar chart using the information from the tables. The bar chart is grouped by days and should display the last seven days.
Earlier i had two tables and used the following query-scheme:
SELECT
t.credits1,
t.credits2,
t.date
FROM
(
(
SELECT
t1.credits1,
t2.credits2,
t1.date
FROM
(
SELECT
SUM(credits) AS credits1,
date
FROM
table1
WHERE
table1.date >= DATE_SUB(CURDATE(), INTERVAL 7 DAY)
GROUP BY
DATE(table1.date)
) t1
LEFT JOIN
(
SELECT
SUM(credits) AS credits2,
date
FROM
table2
WHERE
table2.date >= DATE_SUB(CURDATE(), INTERVAL 7 DAY)
GROUP BY
DATE(table2.date)
) t2
ON t1.date = t2.date
)
UNION
(
SELECT
t1.credits1,
t2.credits2,
t1.date
FROM
(
SELECT
SUM(credits) AS credits1,
date
FROM
table1
WHERE
table1.date >= DATE_SUB(CURDATE(), INTERVAL 7 DAY)
GROUP BY
DATE(table1.date)
) t1
RIGHT JOIN
(
SELECT
SUM(credits) AS credits2,
date
FROM
table2
WHERE
table2.date >= DATE_SUB(CURDATE(), INTERVAL 7 DAY)
GROUP BY
DATE(table2.date)
) t2
ON t1.date = t2.date
)
) t GROUP BY
DATE(date)
(pseudo code)
But how can i do this with more than 2 tables?
Is there any chance to set the dates of the past 7 days as a base, so that i get 7 records everytime?
To point out the problem: If I dont have records in the first table for a day, i won't get the records from the other tables for that day.
I assume the 3 tables have similar schemas? Try using UNION ALL to join the tables together.
SELECT ABB1.date, SUM(ABB1.credit) AS daily_total
FROM
(SELECT date, credits
FROM table1
UNION ALL
SELECT date, credits
FROM table1
UNION ALL
SELECT date, credits
FROM table2) AS ABB1
WHERE DATE >= DATE_SUB(CURDATE(), INTERVAL 7 DAY)