Select count multiple fields within time range - MYSQL - mysql

I have problem with count multiple fields within time range.
I have following table:
# date, count, fb_user_count, email_user_count, reg_dt
'2015-10-27', '11', '6', '5', '2015-11-02 13:59:14'
'2015-10-26', '3', '1', '2', '2015-11-02 13:59:10'
I want to get weekly number of registration with types, like this:
# date, count, fb_user_count, email_user_count, reg_dt
'2015-11-02', '31', '16', '15', '2015-11-02 13:59:14'
'2015-11-09', '12', '6', '6', '2015-11-09 13:59:14'
And monthly:
# date, count, fb_user_count, email_user_count, reg_dt
'2015-11', '131', 'x', 'y', '2015-11-02 13:59:14' (the last value is not so important)
'2015-12', '112', 'x', 'y', '2015-12-09 13:59:14'
I tried different approaches, but I struggle to finish this task. Any help will be great. Thanks!

You can use MySQL Date and Time functions WEEK(), MONTH() and YEAR() to build your queries :
SELECT
MIN(date),
SUM(count),
SUM(fb_user_count),
SUM(email_user_count)
FROM visit
GROUP BY WEEK(date, 1); -- First day is Monday
SELECT
CONCAT(YEAR(date), '-', MONTH(date)),
SUM(count),
SUM(fb_user_count),
SUM(email_user_count)
FROM visit
GROUP BY YEAR(date), MONTH(date);

For your weekly report (on mondays) you can use
select subdate(min(date), 6-weekday(min(date))),
sum(count), sum(fb_user_count), sum(email_user_count), max(reg_dt)
from tablename
group by subdate(date, 6-weekday(date));
and for your monthly report
select concat(year(max(date), '-', month(max(date)),
sum(count), sum(fb_user_count), sum(email_user_count), max(reg_dt)
from tablename
group by year(date), month(date);

Related

Mysql get value without functions

I have this mysql query, I have the following query in mysql, I get a table with the maximum value per day of 8, but I would like to have the value of 08:00 and if that value does not exist use 08:15 and if 08:15 does not exist use the of 08:30 but do not use max or min or average, I need that value.
How can I do?
select month(fecha) as mes, day(fecha) as dia, DATE_FORMAT(fecha, '%m-%d') as mesdia1,
DATE_FORMAT(fecha,'%b %d') mesdia,
cast(max(case when fecha between '2022-01-01' and '2022-12-31' then valor end) as decimal(10,4)) as 'a2022',
cast(max(case when fecha between '2021-01-01' and '2021-12-31' then valor end) as decimal(10,4)) as 'a2021',
cast(max(case when fecha between '2020-01-01' and '2020-12-31' then valor end) as decimal(10,4)) as 'a2020',
cast(max(case when fecha between '2019-01-01' and '2019-12-31' then valor end) as decimal(10,4)) as 'a2019',
cast(max(case when fecha between '2018-01-01' and '2018-12-31' then valor end) as decimal(10,4)) as 'a2018',
cast(max(case when fecha between '2017-01-01' and '2017-12-31' then valor end) as decimal(10,4)) as 'a2017',
cast(max(case when fecha between '2016-01-01' and '2016-12-31' then valor end) as decimal(10,4)) as 'a2016'
from datos
where id_estacion=1 and tipo_sensor=3 and year(fecha) in (2022,2021,2020, 2019,2018,2017,2016) and (hora='08:00' or hora='08:15' or hora='08:30' or hora='08:45')
group by id_estacion,month(fecha), day(fecha)
order by month(fecha), day(fecha)
Thanks
I Add the information requested here.
CREATE TABLE datos (
id_estacion smallint(6) DEFAULT NULL,
tipo_sensor smallint(6) DEFAULT NULL,
valor float DEFAULT NULL,
fecha date DEFAULT NULL,
hora time DEFAULT NULL,
id int(11)
NOT NULL AUTO_INCREMENT,
PRIMARY KEY (id) )
DATA
INSERT INTO `datos` VALUES ('1', '3', '1140.83', '2022-01-04', '08:30:00');
INSERT INTO `datos` VALUES ('1', '3', '1140.791', '2022-01-04', '08:45:00');
INSERT INTO `datos` VALUES ('1', '3', '1140.932', '2022-01-05', '08:00:00');
INSERT INTO `datos` VALUES ('1', '3', '1140.6333', '2022-01-05', '08:15:00');
INSERT INTO `datos` VALUES ('1', '3', '1139.9312', '2022-01-05', '08:30:00');
INSERT INTO `datos` VALUES ('1', '3', '1139.132', '2022-01-05', '08:45:00');
INSERT INTO `datos` VALUES ('1', '3', '1140.032', '2022-01-06', '08:15:00');
INSERT INTO `datos` VALUES ('1', '3', '1140.124', '2022-01-06', '08:45:00');
INSERT INTO `datos` VALUES ('1', '3', '1140.132', '2022-01-07', '08:00:00');
INSERT INTO `datos` VALUES ('1', '3', '1140.08', '2022-01-07', '08:15:00');
INSERT INTO `datos` VALUES ('1', '3', '1139.12', '2022-01-07', '08:30:00');
INSERT INTO `datos` VALUES ('1', '3', '1139.675', '2022-01-07', '08:45:00');
INSERT INTO `datos` VALUES ('1', '3', '1139.575', '2022-01-08', '08:45:00');
I need to get the closest value to 08:00
I think you are over-thinking it. It sounds like you want the minimum time of a given event on a per-day basis.
To simplify, we can just ask for the minimum time on a per-day basis from the raw data. Since you are asking for all years from 2016 to current, I am just asking for the date > '2016-01-01'. No need to be explicit of each individual year. Also, while getting the data, your sample only included those 4 time slots, but I think you dont really care what time it as as long as it was the earliest one of the given day.
That said, my inner query is just pre-gathering the data, pre-grouped by date (month/day, but leaving it as an entire date field), but also grabbing the year of the data for the outer level to simplify use. Also, since the where clause is explicitly only getting data for id_estacion = 1, no need to group by it as they will ALL be that value and thus redundant.
select
month(fecha) rptMonth,
day(fecha) rptDay,
case when d1.FechaYear = 2022 then d1.MaxValor end a2022,
case when d1.FechaYear = 2021 then d1.MaxValor end a2021,
case when d1.FechaYear = 2020 then d1.MaxValor end a2020,
case when d1.FechaYear = 2019 then d1.MaxValor end a2019,
case when d1.FechaYear = 2018 then d1.MaxValor end a2018,
case when d1.FechaYear = 2017 then d1.MaxValor end a2017,
case when d1.FechaYear = 2016 then d1.MaxValor end a2016
from
( select
fecha,
max( year( fecha )) as FechaYear,
min( hora ) MaxHora,
max( valor ) MaxValor
from
datos
where
id_estacion = 1
and tipo_sensor = 3
and fecha > '2016-01-01'
and hora >= '08:00'
group by
fecha ) d1
order by
fecha
Now, this is first pass, but possibly CLOSE to what you want and I will clarify too.
By having the hour column being at or greater than 8am, it will ignore any records with a time such as 2:30am, 5:45am, 7:45am, etc. If you want a cut-off time, such as before 9:00am, then you could easily add "and hora <= '09:00'" to the where clause.
Now, for your "valor" value, you were looking for the maximum value within any respective year. But I am not sure if that is what you mean when you were doing the MAX( case when per year to get the VALOR )... So, if on a given day you have an 8am entry with a valor of 12.35 and an 8:45am entry with 18.85, which valor do you want. Do you want the 18:85 even though it was later in the day? OR, do you want the result line to show the 8am slot that had a valor of 12.35 valor. If the first scenario showing the 18.85, then the query should work for you.
Now, you stated you did not want to use min(), max(), avg(), and dont know why. If you are restricting your time period down, then you are just getting the lowest one that qualified for the time. Similar for the max() of the valor. Since these times and valor amounts are grouped on the PER-DAY, you should be good to just apply which group they fall into in the outer portion of the query. No need to ask for the fecha between two dates. If the year of it is the given one, all done.
Since the inner query is already grouping on a per-day basis, it will only return a single row per day, so the outer query can get the month() and day() context as final output.
Your original group by was by the month and day. Dont know if that was intended or not. If so, then your data would have possibly been returned with
Jan 1 2022
Jan 1 2021
Jan 1 2020
...
Jan 1 2016
Jan 2 2022
Jan 2 2021
...
Jan 2 2016
etc.
If that IS what you intended, then yes, change your group by to the month(), day(), year() respectively, otherwise you can just order by the fecha in ascending or descending order for natural calendar sequential date output.

What is the SQL query to show another date format? [duplicate]

This question already has answers here:
MySQL date format DD/MM/YYYY select query?
(9 answers)
Closed 3 years ago.
I have two MySQL database tabels (named 'accounts' and 'events') with some columns like events.date. This column has a 'date' format. It shows the date as i.e. '2020-02-17'. Now I want to show some data from this combined tables with a query and I want to convert the date formate to DD-MM-YYYY instead of YYYY-MM-DD. I've tried some things but I got errors.
Queries I've tried:
SELECT events.id, convert(varchar, events.date, 105), events.starttime, events.endtime, events.reason, events.created, events.employee, events.employee_id, REPLACE(REPLACE(REPLACE(accounts.location, '1', 'London'), '2', 'Birmingham'), '3', 'Rochdale') location, events.minutes, ROUND((minutes/60), 2) as hours FROM events JOIN accounts ON events.employee_id = accounts.id ORDER BY date
SELECT events.id, convert(date(4), events.date, 20), events.starttime, events.endtime, events.reason, events.created, events.employee, events.employee_id, REPLACE(REPLACE(REPLACE(accounts.location, '1', 'London'), '2', 'Birmingham'), '3', 'Rochdale') location, events.minutes, ROUND((minutes/60), 2) as hours FROM events JOIN accounts ON events.employee_id = accounts.id ORDER BY date
This query works well but shows me the wrong date format:
SELECT events.id, events.date, events.starttime, events.endtime, events.reason, events.created, events.employee, events.employee_id, REPLACE(REPLACE(REPLACE(accounts.location, '1', 'London'), '2', 'Birmingham'), '3', 'Rochdale') location, events.minutes, ROUND((minutes/60), 2) as hours FROM events JOIN accounts ON events.employee_id = accounts.id ORDER BY date
Can you please help me? Many thanks in advance!
You have to use DATE_FORMAT:
SELECT
events.id,
DATE_FORMAT(events.date, '%d-%m-%Y'),
events.starttime,
events.endtime,
events.reason,
events.created,
events.employee,
events.employee_id,
REPLACE(REPLACE(REPLACE(accounts.location, '1', 'London'), '2', 'Birmingham'), '3', 'Rochdale') location,
events.minutes,
ROUND((minutes/60), 2) as hours
FROM events
JOIN accounts ON events.employee_id = accounts.id
ORDER BY date
use FORMAT function
To get DD-MM-YYYY use
SELECT FORMAT (getdate(), 'dd-MM-yyyy ')
read more here: https://learn.microsoft.com/en-us/previous-versions/sql/sql-server-2012/hh213505(v=sql.110)

Count columns on a conditional basis and perform multiplication in one VIEW MYSQL

I have a table of twitter data in MYSQL where the columns is_retweet, is_reply is made of binary values where 1=yes, 0=no. if a user retweeted multiple times in a day, there would then be multiple rows of ones in the retweet coulmn for that user on that day.
account_id, datetime, user_screenname, is_retweet, is_reply,followers_count
'9', '2008-06-11 20:06:35','Access2', '1', '0', '811'
'9', '2008-06-11 23:06:35','Access2', '1', '1', '812'
'9', '2008-06-12 20:01:21','Access2', '0', '1', '813'
'7', '2008-06-11 17:01:00','actingparty', '1', '1', '2000'
I rearrange my sql output to a table below which tells me: for a username on any day, what is the total number of retweets, replies and highest follower count.
account_id, date, user_screenname, sum_retweet, sum_reply, followers_count
'9', '2008-06-11', 'Access2', '2', '0', '812'
'9', '2008-06-12', 'Access2', '0', '1', '813'
Here is my sql code:
CREATE VIEW `tweet_sum` AS
select
`tweets`.`account_id` AS `account_id`,
`tweets`.`user_screenname` AS `user_screenname`,
CAST(`tweets`.`datetime` as date) AS `period`,
MAX(`tweets`.`followers_count`) AS `followers_count`,
SUM(`tweets`.`is_reply`) AS `sum_reply`,
SUM(`tweets`.`is_retweet`) AS `sum_retweet`,
from
`tweets`
group by cast(`tweets`.`datetime` as date), tweets.username
Ultimately, I want to have one more column Reach (which is equal to followers_count times the number of columns(is_retweet, is_reply) that is greater than zero.)
For example, in the output table below, the sum_retweet and sum_reply columns are both greater than zero for 2008-06-11 so i will need to take followers_count*2=1624 for the reach column.
How can i structure my sql code to do that?
account_id, date, user_screenname, sum_retweet, sum_reply, followers_count, **Reach**
'9', '2008-06-11', 'Access2', '2', '1', '812', '1624'
'9', '2008-06-12', 'Access2', '0', '1', '813', '813'
I thought of doing it this way:
1.create a new view
2.count the number of columns that have values >0
3.then take that number multiply by followers count for that day
And the code for that below:
CREATE VIEW tweet_reach AS
SELECT
COUNT(t.sum_reply,t.sum_retweet,t.sun_mention,t.sum_direct,t.sum_mytweet)*t.followers_count AS Reach
FROM information_schema.columns
WHERE table_name='tweet_sum' t AND
t.sum_reply>0 OR
t.sum_retweet>0 OR
t.sun_mention>0 OR
t.sum_direct>0 OR
t.sum_mytweet>0;
This code is wrong but hoping to do something like this. Is it possible?
Thanks,
J
You can do this easily by adding a column in your existing view:
CREATE VIEW `tweet_sum` AS
select `tweets`.`account_id` AS `account_id`,
`tweets`.`user_screenname` AS `user_screenname`,
CAST(`tweets`.`datetime` as date) AS `period`,
MAX(`tweets`.`followers_count`) AS `followers_count`,
SUM(`tweets`.`is_reply`) AS `sum_reply`,
SUM(`tweets`.`is_retweet`) AS `sum_retweet`,
MAX(`tweets`.`followers_count`) * ((SUM(`tweets`.`is_reply`) > 0) + (SUM(`tweets`.`is_retweet`) > 0)) as reach
from `tweets`
group by cast(`tweets`.`datetime` as date), tweets.username;
MySQL treats a boolean expression such as x = y as the integer 1 when true and 0 when false. So, you can just add them together for your multiplication factor.

summation and grouping multiple columns in mysql

I have a table of twitter data in MYSQL where the columns is_retweet, is_reply is made of binary values where 1=yes, 0=no. if a user retweeted multiple times in a day, there would then be multiple rows of ones in the retweet coulmn for that user on that day.
account_id, datetime, user_screenname, is_retweet, is_reply,followers_count
'9', '2008-06-11 20:06:35','Access2', '1', '0', '811'
'9', '2008-06-11 23:06:35','Access2', '1', '1', '812'
'9', '2008-06-12 20:01:21','Access2', '0', '1', '813'
'7', '2008-06-11 17:01:00','actingparty', '1', '1', '2000'
How should i structure my SQL view to give me a result like the table below where i can sum up the retweets and replies for any given day, and by username?
IE What i am trying to do is:
-for a username on any day, what is the total number of retweets, replies and highest follower count.
account_id, date, user_screenname, sum_retweet, sum_reply, followers_count
'9', '2008-06-11', 'Access2', '2', '0', '812'
'9', '2008-06-12', 'Access2', '0', '1', '813'
Here is my sql code:
CREATE VIEW `tweet_sum` AS
select
`tweets`.`account_id` AS `account_id`,
`tweets`.`user_screenname` AS `user_screenname`,
CAST(`tweets`.`datetime` as date) AS `period`,
MAX(`tweets`.`followers_count`) AS `followers_count`,
SUM(`tweets`.`is_reply`) AS `sum_reply`,
SUM(`tweets`.`is_retweet`) AS `sum_retweet`,
from
`tweets`
group by cast(`tweets`.`datetime` as date)
However my data dont seem to match with what i want as it seems that the sql is summing up all users retweets for that day. How can i group it by day and username as well?
Thanks!
J
******EDIT*************************************
I would like to extend the question. Say I have one more column Reach (which is equal to followers_count times the number of columns(is_retweet, is_reply) that is greater than zero.)
For example, in the output table below, the sum_retweet and sum_reply columns are both greater than zero for 2008-06-11 so i will need to take followers_count*2=1624 for the reach column.
How can i structure my sql code to do that?
account_id, date, user_screenname, sum_retweet, sum_reply, followers_count, **Reach**
'9', '2008-06-11', 'Access2', '2', '1', '812', '1624'
'9', '2008-06-12', 'Access2', '0', '1', '813', '813'
just change your GROUP BY to
group by
`tweets`.`account_id`,
`tweets`.`user_screenname`,
cast(`tweets`.`datetime` as date)

Mysql Calculate time difference between timestamps in same field?

Is it possible to calculate the time difference from a timestamp in the same field? My SQL knowledge isn't bad, but I can't figure out how I'd go about doing such a thing on the same table.
ID, SENSOR, COUNT, TIMESTAMP
'1461630', '1', '91', '2013-08-02 09:14:30'
'1461629', '1', '92', '2013-08-02 09:13:29'
'1461628', '1', '92', '2013-08-02 09:12:27'
'1461627', '1', '91', '2013-08-02 09:11:26'
'1461626', '1', '91', '2013-08-02 09:10:24'
'1461625', '1', '7', '2013-08-02 09:03:14'
'1461624', '1', '13', '2013-08-02 09:02:12'
'1461623', '1', '13', '2013-08-02 09:01:11'
'1461622', '1', '7', '2013-08-02 09:00:09'
'1461621', '1', '3', '2013-08-02 08:58:06'
What I need to do, is display a pie-chart with UP vs Down time values. I only have 1 table to reference, so it would all have to be on minute intervals, given only the timestamp above.
Specifically, with the times below, the machine wasn't running for around 7 mins. It's this 7 mins I have to figure out.
'1461626', '1', '91', '2013-08-02 09:10:24'
'1461625', '1', '7', '2013-08-02 09:03:14'
Is this possible? Or would I really need a blow-by-blow account in a separate table? Obviously, I'd rather not create more tables, because the device I'm working with is really quite limited, and it's already a massive hit for it to report this data to a tcp server I have running.
Obviously TIMESTAMPDIFF(,) doesn't work as I need two reference points, whereas I've only got the one. I'm imagining some kind of dodgy sub-select scenario, but I'm not sure.
Cheers!
You can self-join the table, something like this works in your case:
SELECT
*
FROM
yourTable a
INNER JOIN yourTable b ON a.ID = b.ID + 1
WHERE TIMESTAMPDIFF(second, a.timestamp, b.timestamp) > 60
But this can get ugly when you have gaps in your ID column. And especially it can get ugly (in terms of performance (when you don't have good indexes on the table)) when you have *lots of data.
So, I'd suggest using a bit more advanced queries using variables. Without the need to join the table to itself this typically runs pretty fast:
SELECT * FROM (
SELECT
yt.*,
TIMESTAMPDIFF(second, #prevTS, `timestamp`) AS timedifference,
#prevTS:=yt.`timestamp`
FROM
yourTable yt
, (SELECT #prevTS:=(SELECT MIN(`timestamp`) FROM yourTable)) vars
ORDER BY ID
)subquery_alias
WHERE timedifference > 65
see it working live in sqlfiddle
To further improve this query to display the two rows where timedifference is too big shouldn't be a problem :) When you get in serious trouble, feel free to ask, though.