'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

result table



Solution 1:[1]

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.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 DRapp