fetch next last n element from table using my sql - mysql

I have a table like this to track visits of my site hourly:
id | year | month | day | hour | date | visit
1 1391 12 1 10 2012-11-10 15
... ... ... ... ... ... ...
I use this query to fetch last 7 days visitors amount.
SELECT Sum(visit), `day`, `month`, `year`, WEEKDAY(date) as wd
FROM tablename GROUP BY date ORDER BY date DESC LIMIT 7;
Now my question is this: how can i fetch 7 days before this 7 days?
(the year,day,month is my local date format and i want to change it one time on registering)

Use offset:
SELECT Sum(visit), `day`, `month`, `year`, WEEKDAY(date) as wd
FROM tablename
GROUP BY date
ORDER BY date DESC
LIMIT 7 OFFSET 7;

I don't like the idea of using LIMIT here to get the last 7 days, I much prefer a WHERE clause.
I would change your query above to:
SELECT SUM(visit), `day`, `month`, `year`, WEEKDAY(date) as wd
FROM tablename
WHERE date >= CURDATE() - INTERVAL 7 DAYS
GROUP BY date
ORDER BY date DESC;
Then to get the previous 7 days:
SELECT SUM(visit), `day`, `month`, `year`, WEEKDAY(date) as wd
FROM tablename
WHERE date BETWEEN CURDATE() - INTERVAL 14 DAYS AND CURDATE() - INTERVAL 8 DAYS
GROUP BY date
ORDER BY date DESC;
I also don't like the idea of storing your local date format in the table.. you are duplicating data and it should be easy enough to convert the date when querying.

Related

Count Number of a Specific Day(s) Between Two Dates

I have a single line in MySQL table: volunteers
user_id | start_date | end_date
11122 | 2017-04-20 | 2018-02-17
How can I find how many times the 3rd day or 24th day of a month appears? (i.e. 2017-05-03, 2017-06-03, 2017-12-24, 2018-01-24) I'm trying to get to the following count:
Sample Output:
user_id | number_of_third_day | number_of_twenty_fourth_day
11122 | 10 | 10
I look at the documentation online to see if there is a way I can say (pseudo):
SELECT
day, COUNT(*)
FROM volunteers
WHERE day(between(start_date, end_date)) in (3,24)
I tried to create a calendar table to no avail, but I would try to get the days, GROUP BY day, and COUNT(*) times that day appears in the range
WITH calendar AS (
SELECT start_date AS date
FROM volunteers
UNION ALL
SELECT DATE_ADD(start_date, INTERVAL 1 DAY) as date
FROM volunteers
WHERE DATE_ADD(start_date, INTERVAL 1 DAY) <= end_date
)
SELECT date FROM calendar;
Thanks for any help!
This one is more optimized since I generate date range by months not days as other questions, so its faster
WITH RECURSIVE cte AS
(
SELECT user_id, DATE_FORMAT(start_date, '%Y-%m-03') as third_day,
DATE_FORMAT(start_date, '%Y-%m-24') as twenty_fourth_day,
start_date, end_date
FROM table1
UNION ALL
SELECT user_id,
DATE_FORMAT(third_day + INTERVAL 1 MONTH, '%Y-%m-03') as third_day,
DATE_FORMAT(twenty_fourth_day + INTERVAL 1 MONTH, '%Y-%m-24') as twenty_fourth_day,
start_date, end_date
FROM cte
WHERE third_day + INTERVAL 1 MONTH <= end_date
)
SELECT user_id,
SUM(CASE WHEN third_day BETWEEN start_date AND end_date THEN 1 ELSE 0 END) AS number_of_third_day,
SUM(CASE WHEN twenty_fourth_day BETWEEN start_date AND end_date THEN 1 ELSE 0 END) AS number_of_twenty_fourth_day
FROM cte
GROUP BY user_id;
Demo here
A dynamic approach is.
but creating the dateranges, takes a lot of time, so you should have a date table to get the dates
CREATE TABLE table1
(`user_id` int, `start_date` varchar(10), `end_date` varchar(10))
;
INSERT INTO table1
(`user_id`, `start_date`, `end_date`)
VALUES
(11122, '2017-04-20', '2018-02-17')
,(11123, '2019-04-20', '2020-02-17')
;
Records: 2 Duplicates: 0 Warnings: 0
WITH RECURSIVE cte AS (
SELECT
user_id,
`start_date` as date_run ,
`end_date`
FROM table1
UNION ALL
SELECT
user_id,
DATE_ADD(cte.date_run, INTERVAL 1 DAY),
end_date
FROM cte
WHERE DATE_ADD(date_run, INTERVAL 1 DAY) <= end_date
)SELECT user_id,
SUM(DAYOFMONTH(date_run) = 3) as day_3th,
SUM(DAYOFMONTH(date_run) = 24) as day_24th
FROM cte
GROUP BY user_id
user_id
day_3th
day_24th
11122
10
10
11123
10
10
fiddle
In last MySQL version you can use recursion:
-- get list of all dates in interval
with recursive dates(d) as (
select '2017-04-20'
union all
select date_add(d, interval 1 day) from dates where d < '2018-02-17'
) select
-- calculate
sum(day(d) = 10) days_10,
sum(day(d) = 24) days_24
from dates
-- filter 10 & 24 days
where day(d) = 10 or day(d) = 24;
https://sqlize.online/sql/mysql80/c00eb7de69d011a85502fa538d64d22c/
As long as you are looking for days that occur in every month (so not the 29th or beyond), this is just straightforward math. The number of whole calendar months between two dates (exclusive) is:
timestampdiff(month,start_date,end_date) - (day(start_date) <= day(end_date))
Then add one if the start month includes the target day and one if the end month includes it:
timestampdiff(month,start_date,end_date) - (day(start_date) <= day(end_date))
+ (day(start_date) <= 3) + (day(end_date) >= 3)

Sql query to fetch the number of visitors per day since the last 7 days only

I have a database table visitors with three columns:
id | Name | checkin_date |
1 | Reg | 2018-04-20T08:28:54.446Z |
2 | Meg | 2018-04-21T08:28:54.446Z |
3 | Ted | 2018-04-21T08:28:54.446Z |
4 | Bin | 2018-04-23T08:28:54.446Z |
There are several records such as these.
I want to fetch the count of records per each day for only the past 7 days. Right now i was able to fetch the count of visitors per day for all the dates using :
select count(id) as no_of_users
, DATE_FORMAT(checkin_date, '%d %b, %Y') as date
from visitors
GROUP
BY DATE(checkin_date)
But this displays the count of users per each day of all the records. How to get the records of only past 7 days.
select count(id) as no_of_users, DATE_FORMAT(checkin_date, '%d %b, %Y') as date from visitors
where checkin_date >= DATE(NOW()) - INTERVAL 7 DAY
GROUP BY DATE(checkin_date)
in the where is where you want to do the date field >= last 7 days
From your question.
You need to create a calendar table, then LEFT JOIN on the calendar table.
SELECT DATE(t.dt),count(t1.id) cnt
FROM
(
SELECT NOW() dt
UNION ALL
SELECT NOW() - INTERVAL 1 DAY
UNION ALL
SELECT NOW() - INTERVAL 2 DAY
UNION ALL
SELECT NOW() - INTERVAL 3 DAY
UNION ALL
SELECT NOW() - INTERVAL 4 DAY
UNION ALL
SELECT NOW() - INTERVAL 5 DAY
UNION ALL
SELECT NOW() - INTERVAL 6 DAY
UNION ALL
SELECT NOW() - INTERVAL 7 DAY
) t LEFT JOIN T t1
ON DATE(t.dt) = DATE(t1.checkin_date)
group by t1.name,DATE(t.dt)
sqlfiddle:http://sqlfiddle.com/#!9/59f49b/5
select id, count(id) as TOTAL, min (checkin_date) as no_of_users
from visitors
where checkin_date between '<Start Date>' and '<End Date>'
GROUP
BY Id,checkin_date

Whats wrong with my SQL Query? (not getting desired o/p)

I want my query to return number of users registered in a particular day between current date and 7 days before. Instead of days, in date-time format it shows it in integer format. Example, for date 20/12/2012 its showing as 0, 21/12/2012 as 1 and so on
My Query:
select date(update_timestamp) between date_sub(sysdate(), interval 7 day) and sysdate() as date, count(*) users
from registered
group by date(update_timestamp)
Desired Output
DATE | USERS
20/12/2012 | 5
21/12/2012 | 6
Output i'm getting
DATE | USERS
0 | 5
1 | 6
What is wrong with my sql query? Also, i need to know the alternate way of fetching last 7 days data
You have put the condition in the select statement, so it will be evaluated and returned, instead of limiting the result. Put the condition in the where statement:
select date(update_timestamp) as date, count(*) users
from registered
where date(update_timestamp) between date_sub(sysdate(), interval 7 day) and sysdate()
group by date(update_timestamp)
To get all the dates in the interval even if there are no users, you need to join in another source of data:
select date_sub(sysdate(), interval d.offset day) date, count(r.update_timestamp) users
from registered r
inner join (
select 0 as offset union all
select 1 union all
select 2 union all
select 3 union all
select 4 union all
select 5 union all
select 6 union all
select 7
) d on date(r.update_timestamp) = date_sub(sysdate(), interval d.offset day)
group by date_sub(sysdate(), interval d.offset day)
I think you want a WHERE clause:
select date(update_timestamp) Date, count(*) users
from registered
where date(update_timestamp) between date_sub(sysdate(), interval 7 day) and sysdate()
group by date(update_timestamp)
try this query ::
where clause is the filtering part, For the date type logic you should use your current day - 7 days logic in that part of the query.
select date(update_timestamp) ,count(*) users
from registered
where date(update_timestamp)
between
date_sub(sysdate(), interval 7 day) and sysdate()
group by date(update_timestamp)

MySQL COUNT for days

I want to get the value of users visiting my page for 10 days in a chart. I need to COUNT() all the values from the last ten days.
The best layout would be
Day|COUNT(ip)
1 - 10
2 - 12
3 - 52
......
I hope you understand what I mean.
Can MySQL do this directly or need I to do this in PHP in 10 seperate querys?
Regards,
Moritz
Update with Tablestructure:
Id (Auto Increment)|Time (Unix Timestamp)|Ip|Referer
This should run fast for you
SELECT COUNT(ip) ipcount,dt FROM
(
SELECT ip,DATE(FROM_UNIXTIME(`Time`)) as dt FROM mytable
WHERE `Time` > TO_UNIXTIME(NOW() - INTERVAL 10 DAY)
) A GROUP BY dt;
Make sure you have an index on Time
ALTER TABLE mytable ADD INDEX TimeIndex (`Time`);
This will give you results with actual date values:
SELECT
COUNT(DISTINCT ip),
FROM_UNIXTIME(Time, '%m/%d/%Y') AS Day
FROM
tbl
WHERE
Time >= UNIX_TIMESTAMP(DATE_ADD(CURDATE(), INTERVAL -10 DAY))
GROUP BY
FROM_UNIXTIME(Time, '%m/%d/%Y')
try this:
SELECT CAST(DATE(FROM_UNIXTIME(`Time`)) AS CHAR) as dateoftime, COUNT(Ip) as cnt
FROM tablename
WHERE DATE(FROM_UNIXTIME(`Time`)) > DATE_SUB(current_timestamp, INTERVAL 10 DAY)
GROUP BY CAST(DATE(FROM_UNIXTIME(`Time`)) AS CHAR)

group by day for the past 5 days

I am trying to select the sum of an integer field for the past 5 days, and I need to group it for each day.
I'm having a bit of issues figuring out the grouping. Here's my sql query so far:
select
sum(`amount_sale`) as total
from `sales`
where the_date >= unix_timestamp((CURDATE() - INTERVAL 5 DAY))
that works fine for generating the sum for all 5 days together, but I need to break this down so that it shows the sum for each of the past 5 days i.e:
day 1 - $200
day 2- $500
day 3 - $20
etc.
SELECT DATE(FROM_UNIXTIME(the_date)) AS dt, SUM(amount_sale) AS total
FROM sales
WHERE the_date >= UNIX_TIMESTAMP((CURDATE() - INTERVAL 5 DAY))
GROUP BY
dt
To returns 0 for missing dates:
SELECT dt, COALESCE(SUM(amount_sale), 0) AS total
FROM (
SELECT CURDATE() - INTERVAL 1 DAY AS dt
UNION ALL
SELECT CURDATE() - INTERVAL 2 DAY AS dt
UNION ALL
SELECT CURDATE() - INTERVAL 3 DAY AS dt
UNION ALL
SELECT CURDATE() - INTERVAL 4 DAY AS dt
UNION ALL
SELECT CURDATE() - INTERVAL 5 DAY AS dt
) d
LEFT JOIN
sales
ON the_date >= UNIX_TIMESTAMP(dt)
AND the_date < UNIX_TIMESTAMP(dt + INTERVAL 1 DAY)
GROUP BY
dt
This is not a very elegant solution, however, MySQL lacks a way to generate recordsets from scratch.
use the format function to return weekday nr: SELECT DATE_FORMAT(the_date, '%w');
use between
like select * from XXX where date between date(...) and date(...) group by date Limit 0,5
should do it