Sum over Timerange overlapping to next day over several days - mysql

I am desperately trying to get sum of values from range of time over several days, the problem is the range overlaps a day e.g from 15:00 to 10:00 but unfortunately I cant come up with another solution than a loop over all days but there sure is a more elegant way to do this all in one query.
For a single day I have something like this
SELECT
(Date(`Date`)) AS `Date`, SUM(`Val`), `Ld_id`
FROM
(SELECT
`Date`, SUM(`Val`) AS `Val`, `Ld_id`
FROM
`tblVals`
INNER JOIN (SELECT
*
FROM
`tblDate`
WHERE
`Date` BETWEEN (SELECT CONCAT('2011-08-26 ', '14:31:00'))
AND (SELECT CONCAT('2011-08-27 ', '10:01:00'))
ORDER BY `Date` ASC) AS `A` ON `tblVals`.`date_id` = `A`.`date_id`
WHERE
`Ld_id` BETWEEN (SELECT
MIN(`Ld_id`)
FROM
`tblLr`
WHERE
`s_id` = '1') AND (SELECT
MAX(`Ld_id`)
FROM
`tblLr`
WHERE
`s_id` = '1')
GROUP BY ((60/30)*HOUR(`Date`)+FLOOR(MINUTE(`Date`)/30)),`Ld_id`
ORDER BY `Ld_id` ASC ,`Date` ASC) AS `A`
Group by `Ld_id`
Many thanks in advance for any hint`

If you want 15:00 to 14:59 the next day:
- subtract 15 hours from all timestamps
- group by the date part of the timestamp
If you want 15:00 to 10:00 the next day:
- subtract 15 hours from all timestamps
- discard all records where the timepart is now greater than 19:00
- group by the date part of the timestamp
In MySQL, I think it's something like this...
SELECT
DATE(DATE_SUB('Date', INTERVAL 15 HOUR)),
SUM(VAL)
FROM
tblVals
WHERE
TIME(DATE_SUB('Date', INTERVAL 15 HOUR)) < '19:00'
GROUP BY
DATE(DATE_SUB('Date', INTERVAL 15 HOUR))

Related

MySQL Get Orders From Last 12 Weeks Monday to Sunday

I have a table that stores each order made by a user, recording the date it was made , the amount and the user id. I am trying to create a query that returns the weekly transactions from Monday to Sunday for the last 12 weeks for a particular user. I am using the following query:
SELECT COUNT(*) AS Orders,
SUM(amount) AS Total,
DATE_FORMAT(transaction_date,'%m/%Y') AS Week
FROM shop_orders
WHERE user_id = 123
AND transaction_date >= now()-interval 3 month
GROUP BY YEAR(transaction_date), WEEKOFYEAR(transaction_date)
ORDER BY DATE_FORMAT(transaction_date,'%m/%Y') ASC
This produces the following result:
This however does not return the weeks where the user has made 0 orders, does not sum the orders from Monday to Sunday and does not return the weeks ordered from 1 to 12. Is there a way to achieve these things?
One way to accomplish this is with an self outer join (in this case, I use a right outer join, but of course a left outer join would work as well).
To start your weeks on Monday, subtract the result of WEEKDAY from your column transaction_date with DATE_SUB, as proposed in the most upvoted answer here.
SELECT
COALESCE(t1.Orders, 0) AS `Orders`,
COALESCE(t1.Total, 0) AS `Total`,
t2.Week AS `Week`
FROM
(
SELECT
COUNT(*) AS `Orders`,
SUM(amount) AS `Total`,
DATE(DATE_SUB(transaction_date, INTERVAL(WEEKDAY(transaction_date)) DAY)) AS `Week`
FROM
shop_orders
WHERE 1=1
AND user_id = 123
AND transaction_date >= NOW() - INTERVAL 12 WEEK
GROUP BY
3
) t1 RIGHT JOIN (
SELECT
DATE(DATE_SUB(transaction_date, INTERVAL(WEEKDAY(transaction_date)) DAY)) AS `Week`
FROM
shop_orders
WHERE
transaction_date >= NOW() - INTERVAL 12 WEEK
GROUP BY
1
ORDER BY
1
) t2 USING (Week)
To return the weeks with no Orders you have to create a table with all the weeks.
For the order order by the same fields in the group by

fetch next last n element from table using my sql

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.

Count number of entries in time interval 1 that appear in time interval 2 - SQL

I am new here and tried to look up the answer to my question but couldn't find anything on it. I am currently learning how to work with SQL queries and am wondering how I can count the amount of unique values that appear in two time intervals?
I have two columns; one is the timestamp while the other is a customer id. What I want to do is to check, for example, the amount of customers that appear in time interval A, let's say January 2014 - February 2014. I then want to see how many of these also appear in another time interval that i specify, for example February 2014-April 2014. If the total sample were 2 people who both bought something in january while only one of them bought something else before the end of April, the count would be 1.
I am a total beginner and tried the query below but it obviously won't return what I want because each entry only having one timestamp makes it not possible to be in two intervals.
SELECT
count(customer_id)
FROM db.table
WHERE time >= date('2014-01-01 00:00:00')
AND time < date('2014-02-01 00:00:00')
AND time >= date('2014-02-01 00:00:00')
AND time < date('2014-05-01 00:00:00')
;
Try this.
select count(distinct t.customer_id) from Table t
INNER JOIN Table t1 on t1.customer_id = t.customer_id
and t1.time >= '2014-01-01 00:00:00' and t1.time<'2014-02-01 00:00:00'
where t.time >='2014-02-01 00:00:00' and t.time<'2014-05-01 00:00:00'
Here's one method of doing this with conditional grouping in an inner-select.
Select Case
When GroupBy = 1 Then 'January - February 2014'
When GroupBy = 2 Then 'February - April 2014'
End As Period,
Count (Customer_Id) As Total
From
(
SELECT Customer_Id,
Case
When Time Between '2014-01-01' And '2014-02-01' Then 1
When Time Between '2014-02-01' And '2014-04-01' Then 2
Else -1
End As GroupBy
From db.Table
) D
Where GroupBy <> -1
Group By GroupBy
Edit: Sorry, misread the question. This will show you those that overlap those two time ranges:
Select Count(Customer_Id)
From db.Table t1
Where Exists
(
Select Customer_Id
From db.Table t2
Where t1.customer_id = t2.customer_id
And t2.Time Between '2014-02-01' And '2014-04-01'
)
And t1.Time Between '2014-01-01' And '2014-02-01'

extract no of click month wise

I am using MySQL. Here is my schema:
bannerstatclick(idBannerStats: integer, Time: Timestamp, idCampaignBanner :char(36))
I am trying to write a query to select the total no of click month wise by using count on idCampaignBanner.
this will not work it will give an error invalid use of group function.
iwill also try this using having clause but it also not work...
SELECT count(idCampaignBanner) AS TotalClicks ,max(`Time`) AS maxdate,(min(`Time`) + INTERVAL 30 DAY)as monthly
FROM newradium.BannerStatsClick
WHERE Time BETWEEN max(`Time`) AND ( max(`Time`)- INTERVAL 30 DAY)
Something like this should work (you need group by clause if you do aggregation)
select count(idCampaignBanner), MONTH(`Time`) as m
from newradium.BannerStatsClick
group by m
SELECT
count(idCampaignBanner) AS TotalClicks
, max(`Time`) AS maxdate
, (min(`Time`) + INTERVAL 30 DAY)as monthly
FROM newradium.BannerStatsClick
WHERE Time <= (Select max(`Time`) FROM newradium.BannerStatsClick)
And Time >= (Select max(`Time`) - INTERVAL 30 DAY FROM newradium.BannerStatsClick)
Technically could get rid of "Time <= (Select max(Time) FROM newradium.BannerStatsClick)", doesn't really affect the selection. But left in in case you needed different range in future

Average posts per hour on MySQL?

I have a number of posts saved into a InnoDB table on MySQL. The table has the columns "id", "date", "user", "content". I wanted to make some statistic graphs, so I ended up using the following query to get the amount of posts per hour of yesterday:
SELECT HOUR(FROM_UNIXTIME(`date`)) AS `hour`, COUNT(date) from fb_posts
WHERE DATE(FROM_UNIXTIME(`date`)) = CURDATE() - INTERVAL 1 DAY GROUP BY hour
This outputs the following data:
I can edit this query to get any day I want. But what I want now is the AVERAGE of each hour of every day, so that if on Day 1 at 00 hours I have 20 posts and on Day 2 at 00 hours I have 40, I want the output to be "30". I'd like to be able to pick date periods as well if it's possible.
Thanks in advance!
You can use a sub-query to group the data by day/hour, then take the average by hour across the sub-query.
Here's an example to give you the average count by hour for the past 7 days:
select the_hour,avg(the_count)
from
(
select date(from_unixtime(`date`)) as the_day,
hour(from_unixtime(`date`)) as the_hour,
count(*) as the_count
from fb_posts
where `date` >= unix_timestamp(current_date() - interval 7 day)
and created_on < unix_timestamp(current_date())
group by the_day,the_hour
) s
group by the_hour
Aggregate the information by date and hour, and then take the average by hour:
select hour, avg(numposts)
from (SELECT date(`date`) as day, HOUR(FROM_UNIXTIME(`date`)) AS `hour`,
count(*) as numposts
from fb_posts
WHERE DATE(FROM_UNIXTIME(`date`)) between <date1> and <date2>
GROUP BY date(`date`), hour
) d
group by hour
order by 1
By the way, I prefer including the explicit order by, since most databases do not order the results of a group by. Mysql happens to be one database that does.
SELECT
HOUR(FROM_UNIXTIME(`date`)) AS `hour`
, COUNT(`id`) \ COUNT(DISTINCT TO_DAYS(`date`)) AS avgHourlyPostCount
FROM fb_posts
WHERE `date` > '2012-01-01' -- your optional date criteria
GROUP BY hour
This gives you a count of all the posts, divided by the number of days, by hour.