month starting another day - mysql

I've been using MONTH() function to get the months and grouping by month, like this example query.
SELECT
t1.ano,
t1.mes,
tempo_extra,
tempo_ativo,
tempo_extra / tempo_ativo AS volume_extra
FROM
(SELECT
YEAR(`data`) AS ano,
MONTH(`data`) AS mes,
SUM(tempo) AS tempo_extra
FROM
rh.aprovacoes
WHERE
(tipo = 'BH' OR tipo = 'HE')
AND estado = 1
AND YEAR(aprovacoes.`data`) = 2016
GROUP BY MONTH(`data`)) AS t1
LEFT JOIN
(SELECT
MONTH(`data`) AS mes, SUM(ativo) AS tempo_ativo
FROM
rh.processamento
GROUP BY MONTH(`data`)) AS t2 ON t1.mes = t2.mes
ORDER BY mes DESC;
How can i make months start on 23rd of the last month and end on 22nd of the current month.
For example, April starting on March 23rd and end on April 22nd.

Simply subtract 22 days from your date and add a month:
(`data` - interval 22 day) + interval 1 month
March 22 => February 28 or 29 => March 28 or 29
March 23 => March 1 => April 1
April 22 => March 31 => April 30
April 23 => April 1 => May 1
SQL fiddle: http://sqlfiddle.com/#!9/9eecb7d/54883
Your query joins records regardless of the year by the way. I don't think this is desired, so in below query I've corrected this.
SELECT t1.ano, t1.mes, tempo_extra, tempo_ativo, tempo_extra/tempo_ativo AS volume_extra
FROM
(
SELECT
YEAR(data - interval 22 day + interval 1 month) AS ano,
MONTH(data - interval 22 day + interval 1 month) AS mes,
SUM(tempo) AS tempo_extra
FROM rh.aprovacoes
WHERE (tipo = 'BH' OR tipo = 'HE')
AND estado = 1
AND YEAR(aprovacoes.data - interval 22 day + interval 1 month) = 2016
GROUP BY
YEAR(data - interval 22 day + interval 1 month),
MONTH(data - interval 22 day + interval 1 month)
) AS t1
LEFT JOIN
(
SELECT
YEAR(data - interval 22 day + interval 1 month) AS ano,
MONTH(data - interval 22 day + interval 1 month) AS mes,
SUM(ativo) AS tempo_ativo
FROM rh.processamento
GROUP BY
YEAR(data - interval 22 day + interval 1 month),
MONTH(data - interval 22 day + interval 1 month)
) AS t2 ON t1.ano = t2.ano AND t1.mes = t2.mes
ORDER BY t1.ano DESC, t1.mes DESC;

Related

Query data in time interval that spans two days in mysql

I need to count data for a given <week | month | custom> interval grouped by a given time schedule that possibly spans 2 days. The chunks depends on customers working schedules.
Possible cases (for one month interval) :
all data from June 01, 2022 to July 01, 2022, each day between 08:00 pm and 04:00 am (overnight)
all data from June 01, 2022 to June 30, 2022, each day between 04:00 am and 08:00 pm
all data from June 01, 2022 to June 30, 2022, each day between 00:00 am and 23:59 pm
Here's what I came up with:
WITH RECURSIVE seq AS (
SELECT
0 AS value
UNION ALL
SELECT
value + 1
FROM
seq
WHERE
value < 29
),
period AS (
SELECT
'2022-06-01 20:00' + INTERVAL (value * 24 * 60) MINUTE AS start,
'2022-06-01 20:00' + INTERVAL (value * 24 * 60) MINUTE + INTERVAL (8* 60) MINUTE AS end
FROM seq
ORDER BY value DESC
)
SELECT *
FROM (
SELECT
DATE(sd.timestamp - INTERVAL(LEAST(20, 4)) HOUR) as date,
SUM(...) as count,
FROM sensor_data sd
WHERE sd.timestamp BETWEEN '2022-06-01 20:00' AND '2022-07-01 04:00'
AND HOUR(sd.timestamp) >= 20 AND HOUR(sd.timestamp) < 4
GROUP BY
date
) main_data
INNER JOIN period ON DATE(period.start) = date
Unfortunately in doesn't work for the first case (spans two days). Any ideas?
WITH RECURSIVE
cte AS (
SELECT datetime_from range_from,
datetime_from + INTERVAL range_length HOUR range_till
UNION ALL
SELECT range_from + INTERVAL 1 DAY,
range_till + INTERVAL 1 DAY
FROM cte
WHERE range_till < datetime_till
)
SELECT range_from, range_till, COUNT(*) rows_amount
FROM cte
LEFT JOIN test ON test.dt BETWEEN range_from AND range_till
GROUP BY 1, 2;
DEMO with some explanations.

How to count number of nights booked per month with check-in and check-out dates having different months in SQL?

I have a dataset like the below dataset. I want to find the number of nights each id was occupied per month. For some rows, the check-in and checkout dates are in different months. I want to know how to write a query to have the occupancy per month. For example, for id=1, check-in: 2020-01-26 and checkout date: 2020-03-02. How can I have a table that shows January occupancy: 6, Feb occupancy: 29, and March occupancy: 1
id
check-in
checkout
1
2020-01-26
2020-03-02
2
2020-04-01
2020-04-20
3
2020-06-29
2020-07-03
The outcome should be like this:
id
Month
Occupancy
1
Jan
06
1
Feb
29
1
Mar
01
2
Apr
19
3
Jun
02
3
Jul
02
first, you need a numbers table or tally table , after you can easily to it using this query :
select c.id,
case when m.id <> 0
then adddate(last_day(adddate(checkin_date, interval m.id -1 month)),interval 1 day)
else checkin_date
end as Checkin_date,
case when last_day(adddate(checkin_date, interval m.id month)) > checkout_date
then checkout_date
else last_day(adddate(checkin_date, interval m.id month))
end checout_date,
datediff(case when last_day(adddate(checkin_date, interval m.id month)) > checkout_date
then checkout_date
else last_day(adddate(checkin_date, interval m.id month)) end,
case when m.id <> 0
then last_day(adddate(checkin_date, interval m.id -1 month))
else adddate(checkin_date, interval -1 day) end
) daysdiff
from checkins c
join numbers m on m.id <= period_diff(date_format(checkout_date, "%Y%m"),date_format(checkin_date, "%Y%m"))
order by c.id, checkin_date
this is works for any gap (for more than 1 year)
you can usedate_format to show month :
select
date_format(case when m.id <> 0
then adddate(last_day(adddate(checkin_date, interval m.id -1 month)),interval 1 day)
else checkin_date
end, '%Y %M') as month_year
,sum(datediff(case when last_day(adddate(checkin_date, interval m.id month)) > checkout_date
then checkout_date
else last_day(adddate(checkin_date, interval m.id month)) end,
case when m.id <> 0
then last_day(adddate(checkin_date, interval m.id -1 month))
else adddate(checkin_date, interval -1 day) end
)) Occupancy
from checkins c
join numbers m on m.id <= period_diff(date_format(checkout_date, "%Y%m"),date_format(checkin_date, "%Y%m"))
group by date_format(case when m.id <> 0
then adddate(last_day(adddate(checkin_date, interval m.id -1 month)),interval 1 day)
else checkin_date
end, '%Y %M')
order by month_year
month_year | Occupancy
:------------ | --------:
2020 April | 20
2020 February | 29
2020 January | 6
2020 July | 3
2020 June | 2
2020 March | 2
db<>fiddle here
If I understand correctly, you want month-wise aggregated result of occupied inventory.
You can try below simple aggregate query as based on 'Group by' clause then add more criteria logic based on your need if required
select monthname(check_in) as 'Month', sum(dayofyear(check_out) - dayofyear(check_in)) as 'Occupied_days'
from inventory
where year(check_in)=year(check_out)
group by 1;
Note: Above query will work only for dataset where check_in & check_out happened within same year.
Check sample query output here in Fiddle

display month names as column names in mysql

I want to display year and month names as column names between two dates inside my procedure as below
year jan Feb ......Dec
---- ----- ----- -----
2016 val1 val2 val3
2017 val4 val5 val6
some one help me to do this
You could do something like this if i understand you question correctly to generate the desired resultset.
TIMESTAMPDIFF(DAY.... + INTERVAL 1 MONTH) makes it possible to calculate the days within a month.
Please note that months have to be right in every TIMESTAMPDIFF(DAY, '2016-01-01', '2016-01-01' + INTERVAL 1 MONTH) AS 'Jan' line and it should work.
Query
SELECT
'2016' AS YEAR
, TIMESTAMPDIFF(DAY, '2016-01-01', '2016-01-01' + INTERVAL 1 MONTH) AS 'Jan'
, TIMESTAMPDIFF(DAY, '2016-02-01', '2016-02-01' + INTERVAL 1 MONTH) AS 'Feb'
...
, TIMESTAMPDIFF(DAY, '2016-12-01', '2016-12-01' + INTERVAL 1 MONTH) AS 'Dec'
UNION ALL
SELECT
'2017' AS YEAR
, TIMESTAMPDIFF(DAY, '2017-01-01', '2017-01-01' + INTERVAL 1 MONTH) AS 'Jan'
, TIMESTAMPDIFF(DAY, '2017-02-01', '2017-02-01' + INTERVAL 1 MONTH) AS 'Feb'
...
, TIMESTAMPDIFF(DAY, '2017-12-01', '2017-12-01' + INTERVAL 1 MONTH) AS 'Dec'
Result
year Jan Feb Dec
------ ------ ------ --------
2016 31 29 31
2017 31 28 31
Or this query makes it eazier to add a new year and less code duplication.
Query
SELECT
years.year
, TIMESTAMPDIFF(DAY, CONCAT(years.year, '-01-01'), CONCAT(years.year, '-01-01') + INTERVAL 1 MONTH) AS 'Jan'
, TIMESTAMPDIFF(DAY, CONCAT(years.year, '-02-01'), CONCAT(years.year, '-02-01') + INTERVAL 1 MONTH) AS 'Feb'
...
, TIMESTAMPDIFF(DAY, CONCAT(years.year, '-12-01'), CONCAT(years.year, '-12-01') + INTERVAL 1 MONTH) AS 'Dec'
FROM (
SELECT
'2016' AS YEAR
UNION
ALL
SELECT
'2017' AS YEAR
)
AS years
Result
year Jan Feb Dec
------ ------ ------ --------
2016 31 29 31
2017 31 28 31

select dates on this weekday in the past

I have a list of dates ("start", datetime) and I would like to select all dates where :
today = start + 1 WEEK or
today = start + 2 WEEK or
today = start + 3 WEEK or
today = start + 4 WEEK or
today = start + 5 WEEK or
today = start + 6 WEEK
Maximum is start + 6 weeks.
Any idea ?
setup
create table example
(
id integer primary key not null auto_increment,
start datetime not null
);
insert into example ( start )
values
( date_sub(current_date, interval 1 week) ),
( date_sub(current_date, interval 2 week) ),
( date_sub(current_date, interval 3 week) ),
( date_sub(current_date, interval 4 week) ),
( date_sub(current_date, interval 5 week) ),
( date_sub(current_date, interval 6 week) ),
( date_sub(current_date, interval 6 week) ),
( date_sub(current_date, interval 4 week) ),
( date_sub(current_date, interval 9 week) ),
( date_sub(current_date, interval 12 week) )
;
query
select id, start
from example
where
date(start) in
(
date_sub(current_date, interval 1 week) ,
date_sub(current_date, interval 2 week) ,
date_sub(current_date, interval 3 week) ,
date_sub(current_date, interval 4 week) ,
date_sub(current_date, interval 5 week) ,
date_sub(current_date, interval 6 week)
)
;
output
+----+-----------------------------+
| id | start |
+----+-----------------------------+
| 1 | September, 16 2015 00:00:00 |
| 2 | September, 09 2015 00:00:00 |
| 3 | September, 02 2015 00:00:00 |
| 4 | August, 26 2015 00:00:00 |
| 5 | August, 19 2015 00:00:00 |
| 6 | August, 12 2015 00:00:00 |
| 7 | August, 12 2015 00:00:00 |
| 8 | August, 26 2015 00:00:00 |
+----+-----------------------------+
sqlfiddle
I assume you want a WHERE filter to capture all rows containing start DATETIMEs on this weekday one week ago, and two ... six weeks ago. That's the effect of the logic in your question:
today = start + 1 WEEK or today = start + 2 WEEK or ...
means the same thing as
start = today - 1 WEEK etc.
The thing is, you are using DATETIME values for start. They're not guaranteed to be start = CURDATE() because they may not be at midnight.
So, you need to use the DATE() function to reduce them to midnight values before comparing them. Something like this will work.
WHERE DATE(start) IN (
CURDATE() - INTERVAL 6 WEEK, CURDATE() - INTERVAL 5 WEEK, CURDATE() - INTERVAL 4 WEEK,
CURDATE() - INTERVAL 3 WEEK, CURDATE() - INTERVAL 2 WEEK, CURDATE() - INTERVAL 1 WEEK)
You could also do this -- it picks out all records six weeks old or newer, but not the ones in the most recent week, then picks the ones on today's weekday.
WHERE start >= CURDATE() - INTERVAL 6 WEEK
AND start < CURDATE() - 6 DAY
AND WEEKDAY(CURDATE()) = WEEKDAY(start)
This second formulation will be more efficient if you have a great deal of old data in your table and you have an index on your start column: the first two where clauses are sargeable.
Pro tip: When specifying this kind of date filter, the more effort you spend making your specification exact before you write code, the faster you will finish your work. That's true even if you don't count debugging time.
Could you use between?
So...
today BETWEEN start AND start + INTERVAL 6 WEEK
Something like that?
Try To run this query in mysql,
use dbname;
create table adddate
(
id integer primary key not null auto_increment,
initial datetime not null
)auto_increment=100;
insert into adddate ( initial )
values( DATE_ADD(current_date, interval 1 week) ),
( DATE_ADD(current_date, interval 2 week) ),
( DATE_ADD(current_date, interval 3 week) ),
( DATE_ADD(current_date, interval 4 week) ),
( DATE_ADD(current_date, interval 5 week) ),
( DATE_ADD(current_date, interval 6 week) )
;
date_add is an SQLfunction it is used to do addition operations on date
The syntax is:-
DATE_ADD(date,INTERVAL expr type)
the type can be:-
MICROSECOND,
SECOND,
MINUTE,
HOUR,
DAY,
WEEK,
MONTH,
QUARTER,
YEAR,
SECOND_MICROSECOND,
MINUTE_MICROSECOND,
MINUTE_SECOND,
HOUR_MICROSECOND,
HOUR_SECOND,
HOUR_MINUTE,
DAY_MICROSECOND,
DAY_SECOND,
DAY_MINUTE,
DAY_HOUR,
YEAR_MONTH;

SELECT between today and yesterday

I'm trying to select between two dates like this:
SELECT p.Code, p.Name, sum(h.PA = 1) AS PA, sum(h.PB = 1) AS PB,
sum(h.PG = 1) AS PG, sum(h.GoedkeuringDoorNew = 'GF') AS GF,
sum(h.GoedkeuringDoorNew = 'SB') AS SB, sum(h.GoedkeuringDoorNew = 'VIA') AS VIA,
sum(h.Blanco) AS Blanco
FROM psthostess p
LEFT JOIN `psttodo-uit` h
ON h.`Hostess Code` = p.Code
AND DATE(h.`afgewerkt tablet datum`) BETWEEN CURDATE()
AND (CURDATE() - INTERVAL 1 DAY)
WHERE p.Indienst = 1 GROUP BY p.Code, p.Name
But I don't get any results.
I want the results of today and yesterday. But when I do this
SELECT *
FROM `psttodo-uit` p
WHERE DATE(p.`afgewerkt tablet datum`) = CURDATE() - INTERVAL 1 DAY
or change CURDATE() - INTERVAL 1 DAY into CURDATE() I get results... How does this come?
WHERE p.`afgewerkt tablet datum` >= CURDATE() - INTERVAL 1 DAY
AND p.`afgewerkt tablet datum` < CURDATE() + INTERVAL 1 DAY
Assuming current date and time is: April 11, 2014 05:30PM, the datetime you need is betweenApril 10, 2014 00:00:00 and April 11, 2014 23:59:59 (inclusive)
CURDATE() - INTERVAL 1 DAY => April 10, 2014 00:00:00
CURDATE() + INTERVAL 1 DAY => April 12, 2014 00:00:00
Select * from emp where joindate between SUBDATE(NOW(),1) and NOW();