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
Related
I have question about a MySQL query that is logging error's since updating the MySQL-5.7.
The error is the "only_full_group_by" which is will spoken off on stackoverflow.
In many answers it's stated not to disable this option but improve your sql query.
The query that I'm using is returning the minimum and maximum values of a counter per hour.
SELECT MAX( counter ) AS max,
MIN( counter ) AS min,
DATE_FORMAT(date_time, '%H:%i') AS dt
FROM table1
WHERE date_time >= NOW() - INTERVAL 1 DAY
GROUP BY YEAR(date_time), MONTH(date_time), DAY(date_time), HOUR(date_time)
as I understand from the error message I'm missing one of the items from the SELECT cause in the GROUP BY cause. But however I restort/remove/add items I'm not getting the result I got before the upgrade to MySQL-5.7.
I tried to subquery the main query to improve the SQL query. But somehow I can't recreate the results.
What is it I'm missing?
MySQL isn't able to determine the functional dependence ... between the expressions in the GROUP BY clause, and the expressions in the SELECT list.
The non-aggregate expression in the SELECT list (DATE_FORMAT(date_time, '%H:%i') includes a minutes component. The GROUP BY clause is going to collapse the rows into groups by just hour. So the value of the minutes is indeterminate... we know it's going to come from some row in the group, but there's no guarantee which one.
(The question reference to ONLY_FULL_GROUP_BY seems to indicate that we've got some understanding of indeterminate values...)
The easiest (fewest) changes fix would be to wrap that expression in a MIN or MAX function.
SELECT MAX(t.counter) AS `max`
, MIN(t.counter) AS `min`
, MIN(DATE_FORMAT(t.date_time,'%H:%i')) AS `dt`
FROM table1 t
WHERE t.date_time >= NOW() - INTERVAL 1 DAY
GROUP
BY YEAR(t.date_time)
, MONTH(t.date_time)
, DAY(t.date_time)
, HOUR(t.date_time)
ORDER
BY YEAR(t.date_time)
, MONTH(t.date_time)
, DAY(t.date_time)
, HOUR(t.date_time)
If we want rows returned in a particular order, we should include an ORDER BY clause, and not rely on MySQL-specific extension or behavior of GROUP BY (which may disappear in future releases.)
It's a bit odd to be doing a GROUP BY year, month, day and not including those values in the SELECT list. (It's not invalid to do that, just kind of strange. The conditions in the WHERE clause are guaranteeing that we don't have more than 24 hours span for date_time.
My preference would to do the GROUP BY on the same expression as the non-aggregate in the SELECT list. If I ever needed more than 24 hours, I'd include the date component:
SELECT MAX(t.counter) AS `max`
, MIN(t.counter) AS `min`
, DATE_FORMAT(t.date_time,'%Y-%m-%d %H:00') + INTERVAL 0 DAY AS `dt`
FROM table1 t
WHERE t.date_time >= NOW() - INTERVAL 1 DAY
GROUP
BY DATE_FORMAT(t.date_time,'%Y-%m-%d %H:00') + INTERVAL 0 DAY
ORDER
BY DATE_FORMAT(t.date_time,'%Y-%m-%d %H:00') + INTERVAL 0 DAY
--or--
if we always know it's just one day's worth of date_time, and we only want to return the hour, then we can group by just the hour. The same expression as in the SELECT list.
SELECT MAX(t.counter) AS `max`
, MIN(t.counter) AS `min`
, DATE_FORMAT(t.date_time,'%H:00') AS `dt`
FROM table1 t
WHERE t.date_time >= NOW() - INTERVAL 1 DAY
GROUP
BY DATE_FORMAT(t.date_time,'%H:00')
, DATE_FORMAT(t.date_time,'%Y-%m-%d %H')
ORDER
BY DATE_FORMAT(t.date_time,'%Y-%m-%d %H')
SELECT MAX( counter ) AS max,
MIN( counter ) AS min,
YEAR(date_time) AS g_year,
MONTH(date_time)AS g_month,
DAY(date_time) AS g_day,
HOUR(date_time) AS g_hour
FROM table1
WHERE date_time >= NOW() - INTERVAL 1 DAY
GROUP BY g_year, g_month, g_day, g_hour
Or you can get rid of redundant data if you always do it for 1 day:
SELECT MAX( counter ) AS max,
MIN( counter ) AS min,
DAY(date_time) AS g_day,
HOUR(date_time) AS g_hour
FROM table1
WHERE date_time >= NOW() - INTERVAL 1 DAY
GROUP BY g_day, g_hour
I have a table in MySQL with some data of a temperature sensor. I have 1 row per minute. I would like to perform a query to know whether there was any span of 1 hour where the average temperature was greater than 4 degrees. I know how to perform a query where a single row was above 4:
SELECT * FROM sensor WHERE t>4
But in my case, I want to know whether there was a 1 hour period where the average temperature was over 4, not only a single row.
Not sure how to write such query...
One method is:
select s.*
from sensor s
where t > 4 and
not exists (select 1
from sensor s2
where s2.datetime >= s.datetime and
s2.datetime < s.datetime + interval 1 hour and
s2.t <= 4
);
EDIT:
Arggh. The question asks about the average temperature, not any temperature (the question is quite clear, I just misread it).
Here is a variation to handle that:
select s.*,
(select avg(s2.t)
from sensor s2
where s2.datetime >= s.datetime and
s2.datetime < s.datetime + interval 1 hour
) as avg_t
from t
having avg_t > 4;
This uses an extension to MySQL where the having clause can make use of a column alias for filtering.
SELECT DATE_FORMAT(DATE_TIME_FIELD, '%Y-%m-%d %H') AS DATE_TIME_HOUR
FROM sensor
GROUP BY DATE_FORMAT(DATE_TIME_FIELD, '%Y-%m-%d %H')
HAVING AVG(T)>4
Another method is:
SELECT *,
AVG(`t`) AS `avg_t`,
DATE_FORMAT(`date`, '%Y-%m-%d %H') AS `date_and_hour`
FROM `sensor`
GROUP BY DATE_FORMAT(`date`, '%Y-%m-%d %H')
HAVING `avg_t` > 4;
i want to extract total no of click time wise (like week wise or month wise) from table bannerstatclick where bannerstatclick table have these column (idBannerStats: integer, Time: Timestamp, idCampaignBanner :char(36)). I want to calculate maximum time as current date then calculate before 30 days date and then find how many no of click between this date range it will not return any output ...
SELECT count(idCampaignBanner) AS TotalClicks
FROM newradium.BannerStatsClick
WHERE Time BETWEEN
(Select max(`Time`) FROM newradium.BannerStatsClick)
And
(select max(`Time`)- INTERVAL 30 DAY FROM newradium.BannerStatsClick);
Try this
set #max_time:= (SELECT max(`Time`) FROM newradium.BannerStatsClick );
SELECT count(idCampaignBanner) AS TotalClicks
FROM newradium.BannerStatsClick
WHERE Time BETWEEN date_add(#max_time, INTERVAL 30 DAY) and #max_time;
set #max_time:= (SELECT max(`Time`) FROM newradium.BannerStatsClick );
SELECT count(idCampaignBanner) AS TotalClicks
FROM newradium.BannerStatsClick
WHERE Time BETWEEN dateadd(day,-30,#max_time) and #max_time
I am trying to count time stamps between two databases but one has overlapping time stamps, due to not my design flaw.
SELECT date(time + INTERVAL 8 HOUR) as day, COUNT(DISTINCT comment)
FROM news.data
GROUP BY day
UNION ALL
SELECT date(time + INTERVAL 8 HOUR) as day, COUNT(DISTINCT comment)
FROM`news-backup`.`data`
GROUP BY day
ORDER BY year(day) desc, day(day) DESC
LIMIT 20
What seems to happen, there are some timestamps in range of both databases so they produce separate counts for certain dates. So it would give count for TODAY from news and news-backup
EX:
date count
2013-1-15 10
2013-1-15 13
2013-1-14 8
2013-1-13 15
What I want is
EX:
date count
2013-1-15 23
2013-1-14 8
2013-1-13 15
Here is a kicker, I need it in a view, so there are some limitations with that (no subqueries allowed). Thoughts? And no I cannot change the data dump sequence that happens between to DBs
You can't put a subquery in a view, but you can put a view in a view.
So:
create view1 as
SELECT date(time + INTERVAL 8 HOUR) as day, 'current' as which, COUNT(DISTINCT comment) as cnt
FROM news.data
GROUP BY day
UNION ALL
SELECT date(time + INTERVAL 8 HOUR) as day, 'backup' as which, COUNT(DISTINCT comment) as cnt
FROM`news-backup`.`data`
GROUP BY day, which
I'm not sure what you logic for combining them is:
create view2 as
select day, max(cnt) -- sum(cnt)? prefer current or backup?
from view1
group by day
ORDER BY day desc
The documentation that bans subqueries is here. Be sure to search for "The SELECT statement cannot contain".
If you have a table of all the dates, the following "absurd" SQL might work:
select c.date,
coalesce( (select count(distinct comment) from news.data where date(time + INTERVAL 8 HOUR) = c.date),
(select count(distinct comment) from news_backup.data where date(time + INTERVAL 8 HOUR) = c.date)
) as NumComments
from calendar c
This version is assuming you want the "new" first, then the backup. If you want the sum, then you would add them.
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.