If the days are less than 15 th of current month then I should get Current month , and after 15 th the. On the should roll to next month.
I m using db2 db
select case when day(current date)<15 then month(current date) else month(current date + 1 month) end from your table
Related
I have a database column giving me information on how often a file comes in.
Frequency_month
-------------
3rd Friday of the month
2nd Tuesday of the month
3rd Thursday of the month
I need to update this column and have it be a timestamp. e.g.
Frequency_month
-------------
2020-05-21 00:00:00
2020-05-11 00:00:00
2020-05-20 00:00:00
How can I accomplish this using postgres PLPGSQL language?
The following yields what your looking for. As far a parsing the Frequency_month it imposes the following restrictions:
The first character in the string is a digit indicating the relative
number.
This is followed 2 characters ordinal spec (st, nd, etc) and a space.
Actually any 3 characters, they are not checked.
Position 5 - 7 con the first 3 characters of the English day of week (dow).
If any of those are not satisfied you will need to change the S1 subquery.
Further it requires you to provide a date of reference. This may be any date in the month of interest. See comment by #sddk.
It proceeds as follows:
Parse the above extracting the week number, day of week, and last
day of the prior month. (S1).
Determine the ISODOW id numbers for the day of week specified and
DOW for last of prior month. (S2).
Using the ISODOW id numbers Determine, determine the first
occurrence of the target day in the target month. (S3).
Adjust the date from #3 by the additional weeks. (S4).
Finally, if the resulting date in #4 in still in the target month
return the date form #4. If it is not the same month then return
null. This occurs when there in no nth dow in the month or the dow
is incorrectly specified.
I have wrapped the above into a SQL function making parameterization easy. See Demo.
create or replace
function frequency_month( frequency_string text
, target_month date
)
returns date
language sql
as $$
with day_names( l_days) as
( values (array['mon','tue','wed','thu','fri','sat','sun']) )
select -- if the calculated date in still in the target month return that date else return null
-- covers invalid week in frequency 6th Friday or 0th Monday
case when extract(month from target_date) = extract (month from target_month)
then target_date
else null
end
from ( -- Advance from first dow in month the number of weeks to desirded dates
--select (first_of_mon + (7*(rel_num-1)) * interval '1 day')::date target_date
select (first_of_mon + (rel_num-1) * interval '1 week')::date target_date
from ( -- with last day of prior month get first DOW week of target month
select case when dow_day_nbr <= from_day_nbr
then (from_date + (dow_day_nbr-from_day_nbr+7) * interval '1 days' )::date
else (from_date + (dow_day_nbr-from_day_nbr) * interval '1 days' )::date
end first_of_mon
, rel_num
from ( -- Pick up ISODOW numbers
select array_position(l_days, (substring(to_char(from_date, 'day'),1,3))) as from_day_nbr
, array_position(l_days, lower(substring(rel_dow,1,3))) as dow_day_nbr
, from_date
, rel_num
from day_names
cross join ( -- get last day of prior month, desired relative day, relative dow
select substr(frequency_string,1,1)::integer rel_num
, lower(substr(frequency_string,5,3)) rel_dow
, (date_trunc('month',target_month) - interval '1 day')::date from_date
) s1
) s2
) s3
) s4;
$$;
Note: The demo also includes a standalone version if a function is not desired.
I am currently writing a Crystal Report that has a DB2 query as its backend. I have finished the query but am stuck on the date portion of it. I am going to be running it twice a month - once on the 16th, and once on the 1st of the next month. Here's how it should work:
If I run it on the 16th of the month, it will give me results from the 1st of that same month to the 15th of that month.
If I run it on the 1st of the next month, it will give me results from the 16th of the previous month to the last day of the previous month.
This comes down a basic bi-monthly report. I've found plenty of hints to do this in T-SQL, but no efficient ways on how to accomplish this in DB2. I'm having a hard time wrapping my head around the logic to get this to consistently work, taking into account differences in month lengths and such.
There are 2 expressions for start and end date of an interval depending on the report date passed, which you may use in your where clause.
The logic is as follows:
1) If the report date is the 1-st day of a month, then:
DATE_START is 16-th of the previous month
DATE_END is the last day of the previous month
2) Otherwise:
DATE_START is 1-st of the current month
DATE_END is 15-th of the current month
SELECT
REPORT_DATE
, CASE DAY(REPORT_DATE) WHEN 1 THEN REPORT_DATE - 1 MONTH + 15 ELSE REPORT_DATE - DAY(REPORT_DATE) + 1 END AS DATE_START
, CASE DAY(REPORT_DATE) WHEN 1 THEN REPORT_DATE - 1 ELSE REPORT_DATE - DAY(REPORT_DATE) + 15 END AS DATE_END
FROM
(
VALUES
DATE('2020-02-01')
, DATE('2020-02-05')
, DATE('2020-02-16')
) T (REPORT_DATE);
The result is:
|REPORT_DATE|DATE_START|DATE_END |
|-----------|----------|----------|
|2020-02-01 |2020-01-16|2020-01-31|
|2020-02-05 |2020-02-01|2020-02-15|
|2020-02-16 |2020-02-01|2020-02-15|
In Db2 (for Unix, Linux and Windows) it could be a WHERE Condition like
WHERE
(CASE WHEN date_part('days', CURRENT date) > 15 THEN yourdatecolum >= this_month(CURRENT date) AND yourdatecolum < this_month(CURRENT date) + 15 days
ELSE yourdatecolum > this_month(CURRENT date) - 1 month + 15 DAYS AND yourdatecolum < this_month(CURRENT date)
END)
Check out the THIS_MONTH function - there are multiple ways to do it. Also DAYS_TO_END_OF_MONTH might be helpful
Hi I would like to store the number of working hours for a given week in a table with,
hours, year, week
so I can aggregate the hours for a week quickly, where week is the ISO week number.
I then want to do a date range filter query on this table, let's say
From 2018-12-24 to 2019-01-21 (year 2018 week 52 to 2019 week 4).
If the user pass the year and week, then I would need to do a range check on a compound index where you compare the year value first, and then the week number.
How should I structure the query and index to efficiently retrieve records with this range?
This is a basic attempt, given a start year and start week, and an end year and end week:
select year, week, hours
from
weekly hours
where((year = 2018 and week >= 52) OR year > 2018) AND
((year = 2019 and week <=3) OR year < 2019)
You can compare more than one column with the <= or >= operator:
select *
from weekly_hours
where (year, week) >= (2018,52)
and (year, week) <= (2019,3);
That query can make use of an index on both columns, e.g.
create index on weekly_hours (year, week);
You can calculate the week as an absolute number and use this for your range queries. An expression index can be used for the absolute week calculation.
create table weekly_hours (
year int,
week int,
hours int
);
insert into weekly_hours
(year, week, hours)
values
(2018, 52, 10),
(2019, 4, 9),
(2019, 10, 9);
-- expression index that generates the absolute week
create index weekly_hours_absweek_idx on weekly_hours((year * 53 + week));
-- range query
select year, week, hours
from weekly_hours
where
year * 53 + week >= 2018 * 53 + 52
and year * 53 + week <= 2019 * 53 + 4;
I wanted to show the forecast dates with the current date plus frequency up to one year in DB2.
date :Current date
if frequency is :2
upto : 2020-01-01
output be like :
2019-05-22,
2019-07-22,
2019-09-22,
2019-11-22
Try the following RCTE:
with t(dt) as (
values current date
union all
select dt + 2 month
from t
where year(dt + 2 month) = year(current date)
)
select dt
from t;
I want to be able to return cars who have a registration date + 14 days and do this every year.
We tried with this:
select *
from cars
where date(date_part('year', current_date)||'-'||date_part('month',
registrationdate)||'-'||date_part('day', registrationdate)) =
current_date + interval '14 days';
But we got problem with year crossing, for example if I have a registration date at 2018-12-20 it won't work.
There is a better solution?
For example, I got this in data :
id | registrationdate
1 | 2017-12-20
2 | 2018-01-15
and I want to be able with a sql request to return registration date + 14 days, every year.
For our example, it needs to return first row when I launch a request on 2018-01-03, 2019-01-03, 2020-01-03, ... and return second row when I launch request 2018-01-29, 2019-01-29, 2020-01-29, ...
I give you the solution, if it can help someone :
select *
from (
select *,
(extract(year from age(registrationdate)) + 1) * interval '1 year' + interval '14 days' + registrationdate "next_rd_day"
from cars
) as cars_with_upcoming_registration_date
where
extract(month from age(current_date, next_rd_day))=0 and extract(day from
age(current_date, next_rd_day))=0
It creates a new column with next occurence based on desired interval and in where condition, you just have to test if month and day are same and it's ok.
Too, it's working great with leap year and date near end of the year.