I'm loking for one logic that might be not accepatable.
But my requirement is I want count of customers(NewCustomers, repeatCustomers) on the basis of previous and current month
Like from this data I want
DATE NAME
2016-01-01 A
2016-01-01 B
2016-01-01 C
2016-01-05 E
2016-01-05 F
2016-01-25 G
2016-01-25 H
2016-02-25 A
2016-02-25 E
2016-02-10 X
2016-02-11 Y
2016-02-13 F
Output like this
MONTH NewCustomer RepeatCustomer CustomerCount of refernece month (Like here is JAN)
FEB 2 3 7
Same will go for next months
Any suggestion ? Thanks !!
I don't know what the reference month is, but you can get the first two columns by combining the first time you see a customer with who visits in each month:
select date_format(c.date, '%Y-%m') as yyyymm,
count(distinct c.name) as NumCustomers,
sum(case when date_format(c.date, '%Y-%m') <> date_format(cc.start_date, '%Y-%m')
then 1 else 0
end) as NumRepeatCustomers
from customers c join
(select c.name, min(c.date) as start_date
from customers c
group by c.name
) cc
on c.name = cc.name
group by date_format(c.date, '%Y-%m')
order by yyyymm;
Related
I have a table that looks like this
id
date registered
date cancelled
1
2021-01-01
2021-03-02
2
2021-01-05
2021-01-21
3
2021-02-04
2021-02-25
4
2021-02-16
2021-03-26
How do I generate a query in mysql that will give me counts of cancelled and registered for each month.
I can do it for just one of the dates but don't know how to combine for both dates.
For eg for a single date I would do this.
SELECT date_format(`users`.`dateregistered`,_utf8'%Y-%m') AS `DateREegistered`, count(0) AS `Registration Count`
FROM `users`
GROUP BY date_format(`users`.`dateregistered`,_utf8'%Y-%m')
But I want something like this
Date
Registered Count
Cancelled Count
2021-01
2
1
2021-02
2
1
2021-03
0
2
Please let me know if you have any ideas.
You can join the distinct months appearing in date registered and date registered to the table and use conditional aggregation:
SELECT t.Date,
SUM(t.Date = date_format(dateregistered, '%Y-%m')) `Registered Count`,
SUM(t.Date = date_format(datecancelled, '%Y-%m')) `Cancelled Count`
FROM (
SELECT date_format(dateregistered, '%Y-%m') Date FROM users
UNION
SELECT date_format(datecancelled, '%Y-%m') FROM users
) t INNER JOIN users u
ON t.Date IN (date_format(dateregistered, '%Y-%m'), date_format(datecancelled, '%Y-%m'))
GROUP BY t.Date
See the demo.
Results:
Date
Registered Count
Cancelled Count
2021-01
2
1
2021-02
2
1
2021-03
0
2
We have a room where we can only have XX number of people inside due to current limitations. They come at different times and stay for a different length of time.
I'm trying to get a sum of people currently inside for each 15-min period for a specific date. The server is MySQL 8.0.21 deployed on AWS RDS.
MySQL 8.0 Table: Booking
ID
Name
PartySize
Date
BookedFrom
BookedTo
1
John
2
2021-01-01
2021-01-01 08:30:00
2021-01-01 10:00:00
2
Mary
4
2021-01-01
2021-01-01 09:00:00
2021-01-01 11:00:00
3
Nick
3
2021-01-01
2021-01-01 10:30:00
2021-01-01 12:30:00
I also have a "helper table" with a time slot for each 24 hour 15-min slot
MySQL Table: Timeslot
ID
Time
1
00:00:00
2
00:15:00
3
00:30:00
35
08:30:00
37
09:00:00
38
09:15:00
For example, when I run this query below, I will get the correct count (6 people) for 09:30. What is the most efficient way to get this result for each 15-min slot? Please note that while the BookedTo (datetime field) value may be past midnight, I will always be only making date specific queries.
SELECT
t.id, b.date, t.time, SUM(b.partysize) AS total
FROM
booking b,
timeslot t
WHERE
b.date = '2021-01-01'
AND t.time = '09:15:00'
AND b.bookedfrom <= '2021-01-01 09:15:00'
AND b.bookedto >= '2021-01-01 09:15:00'
Looking for this output for all times (including zeros)
Slot_ID
Date
Time
Total
33
2021-01-01
08:00:00
0
34
2021-01-01
08:15:00
0
35
2021-01-01
08:30:00
2
36
2021-01-01
08:30:00
2
37
2021-01-01
09:00:00
6
38
2021-01-01
09:15:00
6
SELECT
t.id as slot_id,
coalesce(b.date, '2021-01-01') as date,
t.time,
coalesce(sum(b.partysize),0) as total
FROM
timeslot t
LEFT JOIN booking b
ON t.time >= TIME(b.bookedfrom) AND t.time < TIME(b.bookedto) AND b.date = '2021-01-01'
WHERE
t.time BETWEEN '08:00:00' AND '17:00:00'
GROUP BY
t.id,
b.date,
t.time
Now, you have some confusing other requirements, but basically this works because multiple rows of timeslot will match to a single row of booking because of the time range expressed.
The confusing requirements are, you say it's only for 8-5pm, but "bookings might extend to the next day".. does it mean that a booking will start at 4pm and finish at 9am the next day? in which case you might need to adjust the AND b.date = '2021-01-01' to be more like AND (DATE(b.bookedfrom) = '2021-01-01' OR DATE(b.bookedto) = '2021-01-01') ...
Use a CTE that returns the specific date for which you want the results, which may not be the same as the column Date in Booking and CROSS join it to Timeslot.
The result should be LEFT joined to Booking and then aggregate:
WITH cte(Date) AS (SELECT '2021-01-01')
SELECT t.ID, t.time, c.Date,
COALESCE(SUM(b.PartySize), 0) Total
FROM cte c CROSS JOIN Timeslot t
LEFT JOIN Booking b
ON b.BookedFrom <= CONCAT(c.Date, ' ', t.time)
AND b.BookedTo >= CONCAT(c.Date, ' ', ADDTIME(t.time, '00:15:00'))
WHERE t.time BETWEEN '08:00:00' AND '17:00:00'
GROUP BY t.ID, c.Date, t.time
Since BookedFrom and BookedTo may not contain the same date, it is not safe to compare only the time parts of the 2 columns to the column time of Timeslot.
This is why all these conditions in the ON clause are needed.
See the demo.
this query works great ... if you wanna have all dates for all slots .. you will have to have a date table too (ideally within timeslot -> cross join dates and timeslots) ...
use inner join if you wanna get only matching dates and timeslots ..
SELECT t.id as slot_id
, b.date
, t.time as slot
, sum(ifnull(party_size,0)) as total
FROM test.timeslot t
LEFT JOIN test.booking b
ON t.time BETWEEN time(b.booked_from) AND time(b.booked_to)
GROUP BY t.id
, b.date
, t.time;
for all timeslots and selected dates:
https://www.db-fiddle.com/f/gLt2Fs8HTDUakMahZHxcTi/0
for matching timeslots and dates:
SELECT t.id as slot_id
, b.date
, t.time as slot
, sum(ifnull(party_size,0)) as total
FROM test.timeslot t
JOIN test.booking b
ON t.time BETWEEN time(b.booked_from) AND time(b.booked_to)
GROUP BY t.id
, b.date
, t.time;
Here's my table, showing user names and the timestamp they scored a point:
id user date
1 Aaron 23/02/2012 22:44
2 Betty 23/02/2012 22:47
3 Carlos 24/02/2012 16:01
4 David 28/02/2012 11:40
5 David 28/02/2012 12:32
6 David 28/02/2012 16:59
7 Aaron 2/03/2012 13:46
8 Aaron 30/03/2012 18:37
9 Betty 30/03/2012 19:58
10 Emma 9/04/2012 6:49
11 Emma 9/04/2012 13:19
12 Emma 9/04/2012 18:20
13 Emma 9/04/2012 20:46
14 Aaron 10/04/2012 15:47
15 Betty 10/04/2012 19:15
16 Betty 10/04/2012 20:40
17 Carlos 11/04/2012 9:44
18 Carlos 11/04/2012 20:01
19 David 11/04/2012 23:17
20 David 12/04/2012 17:09
And here is the results table I am trying to achieve, i.e. an x axis showing month-year, and a y axis displaying the number of users who reached a certain points threshold within that month:
date 1 point First time? 2 points First time? 3 points First time? 4 points First time? Total
Feb-12 A,B,C A,B,C D D 4
Mar-12 B A A 3
Apr-12 A,B,C B,C,D B,C,D E E 4
I've only got as far as calculating the total number of points and the total number of distinct scorers within a given month:
SELECT DISTINCT CONCAT (MONTHNAME(date), ' ', YEAR(date)) as 'date', COUNT(id) as total_points, COUNT(distinct referrer_id) as number_of_scorers
from points
group by CONCAT (MONTH(date), ' ', YEAR(date))
order by YEAR(date), MONTH(date)
which is only giving me:
date total_points number_of_scorers
Feb-12 6 4
Mar-12 3 3
etc.
So my questions are:
How can I amend the query to show me which users reached each point threshold within each month?
How can I amend the query to show me which users reached each point threshold for the first time within that month?
Thanks
The basic query you need is this:
select date_format(date, '%Y-%m') as yyyymm, user, count(*) as points
from t
group by date_format(date, '%Y-%m') as yyyymm, user;
This gets the number of points for each user in a month.
The rest is just aggregations, joins, and conditions:
select ymu.yyyymm,
group_concat(case when ymu.points = 1 then user end) as Points1_Users,
group_concat(case when ymu.points = 1 and ymu.yyyymm = u.min_yyyymm then user end) as Points1_Users_First,
group_concat(case when ymu.points = 2 then user end) as Points2_Users,
group_concat(case when ymu.points = 2 and ymu.yyyymm = u.min_yyyymm then user end) as Points2_Users_First
from (select date_format(date, '%Y-%m') as yyyymm, user, count(*) as points
from t
group by date_format(date, '%Y-%m') as yyyymm, user
) ymu join
(select user, min(yyyymm) as min_yyyymm
from (select date_format(date, '%Y-%m') as yyyymm, user, count(*) as points
from t
group by date_format(date, '%Y-%m') as yyyymm, user
) t
group by user
) u
on ymu.user = u.user
group by yyyymm
order by yyyymm;
We have an order table with fields as below e.g.
Timestamp PaymentID OrderID
341231231 6 1
342131231 12 2
123123123 18 3
123123122 14 4
123123143 12 5
433453454 6 6
445456456 18 7
What we want to do is get an output which will give us a month wise report on order count for each Payment Type but the payments are to be clubbed together for e.g. 6,8 PaymentID comes under type C so the count should be added for both in one
and all other PaymentID's come under type P
So the output what we want is like below.
Year Month C_Orders P_Orders
2015 01 0 4
2015 02 4 3
2015 03 1 0
2015 04 2 1
We tried 2 queries but has incorrect outputs
select SUBSTRING(CONVERT_TZ(FROM_UNIXTIME(co.timestamp),'+00:00','+5:30'),1,4) as year,SUBSTRING(CONVERT_TZ(FROM_UNIXTIME(co.timestamp),'+00:00','+5:30'),6,2) as month, co.payment_id, count(co.payment_id) as c_orders,co1.payment_id, count(co1.payment_id) as p_orders from
orders as co, orders as co1
WHERE co.payment_id in (6,18)
AND co1.payment_id not in (6,18)
GROUP BY year,month
AND
select SUBSTRING(CONVERT_TZ(FROM_UNIXTIME(co.timestamp),'+00:00','+5:30'),1,4) as year,SUBSTRING(CONVERT_TZ(FROM_UNIXTIME(co.timestamp),'+00:00','+5:30'),6,2) as month, 'COD', count(co.payment_id) as cod_orders
from
orders as co
WHERE co.timestamp >= UNIX_TIMESTAMP(CONVERT_TZ('2014-01-01 00:00:00','+00:00','+5:30')) AND co.timestamp <= UNIX_TIMESTAMP(CONVERT_TZ('2020-12-31 23:59:59','+00:00','+5:30')) AND co.is_parent_order = 'N' AND co.status IN ('C','G','E','P') AND co.payment_id in (6,18)
GROUP BY year,month
union
select SUBSTRING(CONVERT_TZ(FROM_UNIXTIME(co.timestamp),'+00:00','+5:30'),1,4) as year,SUBSTRING(CONVERT_TZ(FROM_UNIXTIME(co.timestamp),'+00:00','+5:30'),6,2) as month, 'PREPAID', count(co.payment_id) as prepaid_orders
from
orders as co
WHERE co.timestamp >= UNIX_TIMESTAMP(CONVERT_TZ('2014-01-01 00:00:00','+00:00','+5:30')) AND co.timestamp <= UNIX_TIMESTAMP(CONVERT_TZ('2020-12-31 23:59:59','+00:00','+5:30')) AND co.is_parent_order = 'N' AND co.status IN ('C','G','E','P') AND co.payment_id not in (6,18)
GROUP BY year,month
Use a case statement to only sum/count the values when a condition is met.
select year, month,
sum(case when payment_id in (6,18) then 1 else 0 end) as 'payment_id in (6,18)',
count(case when payment_id not in (6,18) then payment_id else null end) as 'payment_id not in (6,18)'
from table
group by 1,2
I have a two tables that look like this
customer table
first last cust_id
John Doe 0
Jane Doe 1
ledger table
posted_date cust_id
2014-01-14 0
2014-01-20 0
2013-12-20 0
2013-12-20 1
2013-11-12 1
2013-11-10 1
I need to calculate the number of months where the customer posted a transaction at least once, this is being called CustomerMonths for the last 12 months. This means CustomerMonths for each cust_id would be between 0 and 12. So for this data I would want to see
cust_id CustomerMonths
0 2
1 2
This is because cust_id 0 was in at least once in Jan 2014 and at least once in Dec 2013.
Similarly, cust_id 1 was in at least once in Dec 2013 and at least once in Nov 2013.
For this example for cust_id 0:
2014-01-14,
2014-01-20 = 1 CustomerMonths
2013-12-20 = 1 CustomerMonths
so total CustomerMonths for last 12 months for cust_id 0 is 2.
I have this working for one month but not sure how to get this to work for the last 12 months. Although I'd settle for it working for the last two months. I think i could figure out the rest. Here's what I have.
select distinct
c.cust_id,
(case when count(lJan.posted_date) = 0 then 0 else
case when count(lJan.posted_date) > 0 then 1 end end) as CustomerMonths
from 'customer' c
left join 'ledger' lJan on (lJan.cust_id = c.cust_id and lJan.posted_date between '2014-01-01' and '2014-01-31')
group by c.cust_id
You need to count distinct months, so use count(distinct). The question is what is the argument. Try this:
select c.cust_id,
count(distinct year(l.posted_date) * 100 + month(l.posted_date)) as CustomerMonths
from customer c left join
ledger l
on l.cust_id = c.cust_id and
l.posted_date between '2013-01-01' and '2014-01-31'
group by c.cust_id;
Another way of writing the select:
select c.cust_id,
count(distinct date_format(l.posted_date, '%Y-%m')) as CustomerMonths