Generate Monthly XML from a table containing date range - mysql

I have a table as -
test_table(booking_id, booking_description, start_date, end_date)
Sample Data -
1 | Some booking | 06/30/2013 | 08/01/2013
2 | Some new one | 08/05/2013 | 09/01/2013
3 | Some new two | 09/03/2013 | 09/05/2013
Now I want to generate a monthly xml file from using some java code (No problem in it, I would write), I would be passing the month and year (basically start and end date of the month) to mysql query and I want some table as -
month = 7, year 2013
1 | Some booking | 07/01/2013
1 | Some booking | 07/02/2013
...
Month = 9, year = 2013
2 | Some new one | 09/01/2013
| | 09/02/2013
3 | Some new two | 09/03/2013
...
I was looking to use a java loop from start date to end date and query mysql to find out whether this date comes in the date range or not, if it comes I would add the details else I would add blanks. But that is going to be horrible approach (will go for 30 times mysql look ups) and I am considering it as last option.
Is there any other way around with one or two mysql query and get the data in the format.
EDIT:
month = 7, year = 2013
Select *
from booking_details
where month(start_date) <= 7 and year(start_date) <= 2013 and
month(end_date) >= 7 and year(end_date) >= 2013
I developed this query but still not sure would it over all the possible scenarios.

Based on my understanding of the question you want something like this:
declare #date datetime
Select booking_id, booking_description, start_date --you don't indicate which date field you want in the results
from test_table
where (start_date between #date and date_add(#date, INTERVAL 1 MONTH))
or (end_date between #date and date_add(#date, INTERVAL 1 MONTH))
SQL is probably not exact, I know TSQL not MySQL but this should be close.

Related

First date of any month in SQL

I am seeking to find first date of the month in the corresponding table:
So if i have 26/08/2011 August as date and 2 months to add, it becomes 26/10/2011. I need the first date of the resulting month- like 01/10/2011.
Can this be achieved in SQL?
Update : I could get the date of the month using
DATEADD(month,months_add, date)
Couldnt get to "beginning of month". Tried: How can I select the first day of a month in SQL?
But for me it throws the error: function pg_catalog.date_diff("unknown", integer, date) does not exist;
You could try using date_add for add two months and date_sub for sub the days -1
set #my_date = "2017-06-15";
SELECT DATE_SUB( DATE_ADD(#my_date, INTERVAL 2 MONTH),
INTERVAL DAYOFMONTH(#my_date)-1 DAY);
SELECT table.date,
table.month_add,
DATE_FORMAT(table.date + INTERVAL table.month_add MONTH,
'%Y-%m-01') AS beginning_of_month
FROM table
Assuming your date is currently a varchar in dd/MM/yyyy format, you can use STR_TO_DATE to convert it to a DATE type column, then use DATE_ADD with your months_add column to dynamically add months then finally use DATE_FORMAT to display it back in a 01/MM/yyyy format with the first day of the month.
SELECT
Date_Column,
Date_Months_Add,
DATE_FORMAT(DATE_ADD(STR_TO_DATE(Date_Column, "%d/%m/%Y" ), INTERVAL Date_Months_Add MONTH), '01/%m/%Y') AS Date_Beginning
FROM sample
Result:
| Date_Column | Date_Months_Add | Date_Beginning |
|-------------|-----------------|-----------------|
| 26/08/2011 | 2 | 01/10/2011 |
| 25/04/2011 | 1 | 01/05/2011 |
| 16/09/2022 | 3 | 01/12/2022 |
| 14/07/2022 | 4 | 01/11/2022 |
Fiddle here.

How to fetch data from specific hours in SQL

I have a problem with CosmosDB, which also allows some SQL queries.
I have a database that is being uploaded every hour with a new record.
I would like to fetch everything from the last day from 8PM to 8AM current day and another query from 8AM to 8PM the current day. I have a timestamp in the db in ISO format. How the potential query (or queries) would look like?
I achieved to fetch last 24h like this, but I really want to stick to the time range 8PM-8AM and then 8AM-8PM, basically two shifts. Previous one and the current one.
function getLast24hTime(){
var date = new Date();
var a = date.setHours(-24);
return a;
}
and then:
SELECT * FROM c where c.time >= udf.getLastHourTime()
tl;dr Everyday I want to fetch specific hours range from the previous day (8pm-8am) + specific hours from the current day (8am-8pm). How.
in mysql you could do
the other shift is analog
CREATE TABLE be (
`date` DATETIME
);
INSERT INTO be
(`date`)
VALUES
('2022-01-13 20:41:24'),
('2022-01-13 21:41:24'),
('2022-01-14 01:41:24'),
('2022-02-14 09:41:24'),
('2022-02-14 10:41:24');
SELECT `date` from be WHERE `date` > CURDATE() - INTERVAL 1 DAY + INTERVAL 20 HOUR
ANd `date` < CURDATE() + INTERVAL 8 HOUR
| date |
| :------------------ |
| 2022-01-13 20:41:24 |
| 2022-01-13 21:41:24 |
| 2022-01-14 01:41:24 |
db<>fiddle here

Dynamic due dates checking with the given period of dates

id start_date interval period
1 1/22/2018 2 month
2 2/25/2018 3 week
3 11/24/2017 3 day
4 7/22/2017 1 year
5 2/25/2018 2 week
the above is my table data sample. start_dates will be expired based on interval and period(i.e id-1 will have due date after 2 months from the start_date, id-2 will have due after 3 weeks vice versa). period is enum of (day,week,month,year). Client can give any period of dates. let's say 25-06-2026 to 13-07-2026 like that.. I have to return the ids whose due dates falls under that period.I hope i made my question clear.
Here what i have done to resolve this. I am using mysql 5.7. I found ways to achieve this with recursive CTE's.(not available in mysql 5.7). and there is a way to achieve this by populating virtual records by using inline sub queries along with unions and its a performance killer and there is restriction of population of records.(like given in the link Generating a series of dates) I have reached a point to get results for a single date which is very easy. Below is my query(in oracle)
select id
from (select a.*,
case
when period='week'
then mod((to_date('22-07-2018','dd-mm-yyyy')-start_date),7*interval)
when period='month' and to_char(to_date('22-07-2018','dd-mm-yyyy'),'dd')=to_char(start_date,'dd')
and mod(months_between(to_date('22-07-2018','dd-mm-yyyy'),start_date),interval)=0
then 0
when period='year' and to_char(to_date('22-07-2018','dd-mm-yyyy'),'dd-mm')=to_char(start_date,'dd-mm')
and mod(months_between(to_date('22-07-2018','dd-mm-yyyy'),start_date)/12,interval)=0
then 0
when period='day'
and mod((to_date('22-07-2018','dd-mm-yyyy')-start_date),interval)=0
then 0 else 1 end filter from kml_subs a)
where filter=0;
But I need to do this for a period of dates not a single date. Any suggestions or solutions will be much appreciated.
Thanks,
Kannan
Assuming this is an Oracle question and not MySQL:
I think the first thing that you need to do is calculate when the due date is. I think a simple case statement can handle that for you:
case when period = 'day' then start_date + numtodsinterval(interval,period)
when period = 'week' then start_date + numtodsinterval(interval*7,'day')
when period = 'month' then add_months(start_date,interval)
when period = 'year' then add_months(start_date,interval*12)
end due_date
Then, using that new due_date field, you can check if the due date falls between the desired date range.
select *
from(
select id,
start_date,
interval,
period,
case when period = 'day' then start_date + numtodsinterval(interval,period)
when period = 'week' then start_date + numtodsinterval(interval*7,'day')
when period = 'month' then add_months(start_date,interval)
when period = 'year' then add_months(start_date,interval*12)
else null end due_date
from data)
where due_date between date '2018-02-25' and date '2018-03-12'
The above query checking between 2/25/18 and 3/12/18 produces the following output using your data:
+----+-------------+----------+--------+-------------+
| id | start_date | interval | period | due_date |
+----+-------------+----------+--------+-------------+
| 2 | 05-FEB-2018 | 3 | week | 26-FEB-2018 |
| 5 | 25-FEB-2018 | 2 | week | 11-MAR-2018 |
+----+-------------+----------+--------+-------------+

How to store business time in database to be able search when it's open?

Lets say shop is working from 8:00 till 23:00 and we use time format. Then it's easy. Some kind of:
where NOW() > start and NOW() < end
But what if shop working until 1:00am next day? And now exactly 23:00; So 23 > 1. This is will not gonna work.
So how to store and search business time in the correct way? Maybe in the end field better to store difference in seconds or i even don't know...
UPD: If you recommend use timestamp, then how i will find this time after one year, for example? We need to convert all dates to one?
The only solution that i decided use for now.
select * from times where
('05:00:00' between opens::time and closes::time) or
(
closes::time < opens::time and
'05:00:00' >= opens::time and
'05:00:00' > closes::time
) or
(
closes::time < opens::time and
opens::time > '05:00:00' and
closes::time > '05:00:00'
) and dow = 4
So for 13:00:00 - 04:00:00 I have results when variable is:
05:00:00 - no results
12:00:00 - no results
00:00:00 - 1 row
01:00:00 - 1 row
18:00:00 - 1 row
If you have any better idea, please share
The only correct way to store business hours is to use iCalendar RRules and ExDates
Store the rules a table. Use a library (Postgres has a few) to generate opening hours for the upcoming year. Use a materialized view for this
This lets you handle things like holidays, being closed on the last Thursday of every month, etc.
Its a little bit unclear what language you are in. But here are some examples. If it is formattet as dateTime from the server to example C#, then you can use: start> date1 && end < date2.
If using MySQL then check this post: MySQL "between" clause not inclusive?
t=# create table shop(i int, opens time, closes time, dow int);
CREATE TABLE
t=# insert into shop select g+10,'11:00','23:00', g from generate_series(1,5,1) g;
INSERT 0 5
t=# insert into shop select 23,'12:00','13:00', 6;
INSERT 0 1
then your logic would work:
t=# select * from shop where now()::time between opens and closes and extract(dow from now())::int = dow;
i | opens | closes | dow
----+----------+----------+-----
14 | 11:00:00 | 23:00:00 | 4
(1 row)
it is open on Thursday ATM.
and example for Satruday on and not on time:
t=# select * from shop where '2017-08-12 12:59'::time between opens and closes and extract(dow from '2017-08-12 12:59'::timestamp)::int = dow;
i | opens | closes | dow
----+----------+----------+-----
23 | 12:00:00 | 13:00:00 | 6
(1 row)
Time: 0.240 ms
t=# select * from shop where '2017-08-12 13:01'::time between opens and closes and extract(dow from '2017-08-12 13:01'::timestamp)::int = dow;
i | opens | closes | dow
---+-------+--------+-----
(0 rows)
You should use TIMESTAMP as data_type for start and end column. then you can use where NOW() > start and NOW() < end. It will work fine.

map sql column to date based on an end date

I have a pay period sybase table containing column names day01 - day14. I also have a column containing the pay period end date. Management is requesting the hours used for all the Mondays in the month of July.
How can I walk the column names mapping them to dates so I can get all Mondays in the month of July using sybase?
data example
Time_Sheet_Hours
day01 | day02 | day03 ... day14 | end_date
7.5 | 7.5 | 0 ... | 2017-07-05
day01 | day02 | day03 ... day14 | end_date
7.5 | 7.5 | 7.5 ... | 2017-07-19
day01 | day02 | day03 ... day14 | end_date
7.5 | 7.5 | 7.5 ... | 2017-08-02
Can you somehow do a nested query where the from could be dynamic based on the column sequence and mapped to a date based on the end_date?
You can use datepart in Sybase, or dayofweek in mysql, to determine the numeric day of the week (Sunday is 1) that end_date falls on. Then you can determine how many more days until "day 2" (Monday - not your "day02" column). Then either use a case statement, or execute a dynamic query, in order to sum up the correct day.
Here is an example in Sybase. It assumes that day14 is also the end_date.
Therefore, if end_date is a Sunday, then that means day14 was also a Sunday, and day01 and day08 represent Mondays.
select
sum
(
case
when (datepart(dw, end_date) = 1) then day01 + day08 -- Ends on Sun
when (datepart(dw, end_date) = 7) then day02 + day09 -- Ends on Sat
when (datepart(dw, end_date) = 6) then day03 + day10 -- Ends on Fri
when (datepart(dw, end_date) = 5) then day04 + day11 -- Ends on Thu
when (datepart(dw, end_date) = 4) then day05 + day12 -- Ends on Wed
when (datepart(dw, end_date) = 3) then day06 + day13 -- Ends on Tue
when (datepart(dw, end_date) = 2) then day07 + day14 -- Ends on Mon
else 0
end
)
from my_table
Bit of brute case when should do it:
SELECT
CASE WHEN dayofweek(end_date - INTERVAL 13 day) = 2 THEN day01 END +
CASE WHEN dayofweek(end_date - INTERVAL 12 day) = 2 THEN day02 END +
... -- and so on. Writing this out on an iPad is a pain
CASE WHEN dayofweek(end_date - INTERVAL 1 day) = 2 THEN day13 END +
CASE WHEN dayofweek(end_date - INTERVAL 0 day) = 2 THEN day14 END
as sum_of_mondays
FROM time sheet
WHERE end_date BETWEEN x AND y
Do please examine this for real with your data; check that the dayofweek() calc on the adjusted date really does correctly identify the Mondays- I've no MySQL instance to try this on but the docs say that dayofweek returns 2 for a Monday, and I've assumed that end_date and day14 are the same day hence subrptracting 0 days from it. If your end_date is midnight after the day upon which day14's hours are worked, then you'll need to adjust the subtracts by one (I.e. Subs should start by subtracting 14, and finish by subtracting 1)
Although this doesn't specifically answer my original question, I'd like to share our end solution. The end solution was to just build a view to query against which contained normalized data.