extract in postgresql date - postgresql

I have a question about extract function in PostgreSQL.
I am generating reports about last month's data.
So far no problem:
where extract (month from date) = extract(month from current_date- '1 month'::interval)
But the problem with this setup is that when the data spans more than 1 year than more months will be included.
To handle this I can add another condition for year:
and extract (year from date) = extract (year from current_date)
But this will cause a problem when generating report about December in January.
How can I generate my report about December in January without the fear that I include more months.

How about this:
WHERE date_trunc('month',date)=date_trunc('month',current_date) - interval '1 month'

Related

Creating flexible date ranges in PostgreSQL

I want to make my query more flexible with dates. I am thinking of defining variables with reference to current date. currently I am coding the exact date for the last quarter, the quarter before and the quarter one year ago.
That is the query for Q1:
select '2020_Q1' as time_frame, id, status, date, agent, country, sale
from sales
where date >= '2020-01-01' and date < '2020-03-31'
I do the same for Q4 and Q1 (2019) and union in the end. Today is April 27, let's say it is 4 months from now and it is August 27th. Now, I would want to look at Q2,Q1 and Q2(2019). I believe, I would need to work with current_date, but let me know if you think there is a more efficient way.
You can use date_trunc() to get the start of the "current quarter":
select ...
from sales
where date => date_trunc('quarter', current_date)
and date < date_trunc('quarter', current_date) + interval '3 months'

How to find the 1st and 3rd Sunday/Monday of a current month in postgresql

Can anyone help me to find the specific week day of the month in postgresql... like 1st and 3rd week sunday/monday or 2nd and 4th week wednesday
First off contrary to initial expectations working with dates is complex, sometime extremely so. The combination of week numbers and days the week fall into the latter category.
The problem stems from the 2 ISO definitions:
All weeks start on Monday and are 7 days long.
The first week of the year is the week containing 4-Jan.
This dooms any effort (at least any reasonable simple onc) to failure. While an admirable effort I'll use #Abelisto suggestion as a sample. See Fiddle. I've changed that just enough to use multiple parameters, while for most months it's correct but look at 30,31-Jan-2019 and Jan-2021.
The problem with the first being while the ISO week is perfectly consistent the calendar is not. This results that the first week of a given month be the same as the last week of the previous month, and the reverse.
While this can usually be worked around by itself not so when combined with the other. As a result of each being 7 days long and the 1st week of the year containing 4-Jan gives rise to the larger problem. The last few days of Dec maybe in the 1st week of the next year. Also the first days of Jan can be in the 52( or 53) week of the prior year (see 2nd query in fiddle). Is there a solution? I'm sure there is somewhere out there. I just don't have it. At least with the Extract function.
So how about this specific issue: Well basically it comes down to getting the last day of the previous month, then finding the next DOW (Sunday or Monday) as needed. Now coming from a Oracle back ground I'd just use the NEXT_DAY function which would do just that for me. Unfortunately Postgres does not provide that useful function. But you can roll your own. Below I provide a a couple functions I wrote to do this functionality in Postgres. It consists of 2 Postgres SQL functions:
- utl_dates_first_dow_of_month(). It takes 2 parameters, the target Day-Of-Week (DOW) as the first 3 characters of the day name (case insensitive) and a date in the desired month. It returns the DATE which is the first occurrence of the requested DOW.
- utl_dates_next_dow(). It takes the same 2 parameters and returns the next calendar date of the specified DOW from the from the specified date. If the date specified fall on the requested DOW the routine DOES NOT return the specified date. Function is actually used by the first.
Fortunately the routines are shorter than the description.
create or replace function utl_dates_next_dow(dow_in text, date_in date)
returns date
language sql
immutable strict
as $$
-- Given a DOW and a date return the calendar date for the next occurrence of DOW
with dy as (select string_to_array('mon,tue,wed,thu,fri,sat,sun', ',') dl)
, dn as (select array_position(dl, (substring(to_char(date_in, 'day'),1,3))) fn
, array_position(dl, lower(substring(dow_in,1,3))) dn
from dy
)
select case when dn <= fn
then (date_in + (dn+7-fn) * interval '1 day')::date
else (date_in + (dn-fn) * interval '1 day')::date
end
from dn;
$$;
create or replace function utl_dates_first_dow_of_month(dow_in text, date_in date)
returns date
language sql
immutable strict
as $$
-- Given a DOW and a Date return the calendar date of the first specified dow in which the specified date falls.
select utl_dates_next_dow(dow_in, (date_trunc('month', date_in) - interval '1 day')::date);
$$;
Now with that out out of the way on the the issue at hand. As Abelisto, and others, indicate the request is ambiguous. There is no such thing as 1st or 3rd Sunday/Monday. Do you want the 1st and 3rd Sunday and the 1st and 3rd Monday of the month? Do you want
Do you want the 1st and 3rd Sunday of the month and the Monday following each respectively. Do you want the Sunday and Monday for the 1st and 3rd week on the month (If so Monday would always be the earlier date, see definition 1 above)? Please try to be more specific with your questions. And include test data - as text no images - and the expected results from that data. The solutions are however just slight modifications of each other. (No solution for the 3rd listed possibility.)
For the case of 1st and 3rd Sunday and the 1st and 3rd Monday:
with parms (dt) as (values ( date '2020-04-01'), (date '2020-06-01') )
, base_dates( fsun, fmon) as
( select utl_dates_first_dow_of_month('Sun',dt)
, utl_dates_first_dow_of_month('Mon',dt)
from parms
)
select '1st & 3rd Sunday and 1st & 3rd Monday'
, fsun "1st Sunday"
, (fsun+interval '14 days')::date "3rd Sunday"
, fmon "1st Monday"
, (fmon+interval '14 days')::date "3rd Monday"
from base_dates;
For the 1st and 3rd Sunday of the month and the Monday following:
with parms (dt) as (values ( date '2020-04-01'), (date '2020-06-01') )
, base_dates( fsun, fmon) as
( select utl_dates_first_dow_of_month('Sun',dt)
, (utl_dates_first_dow_of_month('Sun',dt)+interval '1 day')::date
from parms
)
select '1st & 3rd Sunday and Monday Following '
, fsun "1st Sunday"
, fmon "1st Monday"
, (fsun+interval '14 days')::date "3rd Sunday"
, (fmon+interval '14 days')::date "3rd Monday"
from base_dates;
select * from
(
select dow, i, row_number() over(partition by dow order by i) as rnk from
(
select
extract(dow from i::date) as dow,
i::date
from generate_series('2022-10-01'::date,'2022-10-31'::date,interval '1 Day') i
) tmp where dow = 1
)tmp_out where rnk = 3;

DB2: How do I pull the previous full months' data for a table.column?

I'm running into an issue with a DB2 query for a Crystal Report. What I need to do is to pull the previous full month's data for a column, even if the previous month is December of the previous year (as it would be in January, for example). For instance, I have this table named TABLE:
Name Date
John 11/01/2019
Dave 12/15/2019
Frank 01/02/2020
I would need something like
select DATE from TABLE where month(DATE) = month(x)
In this instance, x = the full previous month's data, which in this case, would be December 2019, so it should return"
Dave 12/15/2019"
What's the code to pull the previous full month's data, regardless of what the current month and year are? Of course it should be dynamic, so it will pull the previous full month's data regardless when the query is run.
Try this
select date from table
where date between last_day(current_date - 1 month) + 1 day - 1 month
and last_day(current_date - 1 month)
or if your version of db2 knows first_day
select date from table
where date between first_day(current_date - 1 month)
and last_day(current_date - 1 month)
I was actually able to pick apart the IBM documentation to use the DB2 version of DATEPART and DATEADD. Here's what I came up with:
WHERE (DATE_PART('MONTH', COLUMN_DATE) = DATE_PART('MONTH', CURRENT_DATE - 1 MONTH) AND
DATE_PART('YEAR', COLUMN_DATE) = DATE_PART('YEAR', CURRENT_DATE - 1 MONTH))
I hope this helps someone in the future.
You may use any date instead of current date to return the first and last days of month previous to this given date.
This works for any Db2 version.
SELECT
CURRENT DATE - DAY(CURRENT DATE) + 1 - 1 MONTH AS FIRST_DAY
, CURRENT DATE - DAY(CURRENT DATE) AS LAST_DAY
FROM SYSIBM.SYSDUMMY1;

How can I pull records for a full month AFTER a specific date?

I have a list of employees and their hire dates. I need to pull revenue records for their first 3 months on the job. For example, if someone is hired on August 6 2018, I need to pull their revenue records for September, October, and November 2018.
I really just need the "where" statement to find the correct dates.
Let's call the tables: bookings, employees
columns: hired_at, booked_at
I originally thought it was first 3 months from hire date, and I used
where bookings.booked_at <= dateadd(month, 3, employees.hire_date)
Upon finding out that I need the 3 months FOLLOWING the hire date, I'm not sure how to write this.
Thanks!
You should use INTERVAL, dateadd isn't supported by PostgreSQL
<= employees.hire_date - Interval '3 months'
You can check the documentation in the following link
https://www.postgresql.org/docs/9.0/functions-datetime.html
WHERE booked_at >= date_trunc('month', hired_at + interval '1 month')
AND booked_at < date_trunc('month', hired_at + interval '3 month')
where date_trunc('month', ...) always gives you the 1st of the month.

how would I query 4/1/ of the 72nd birth date year > an input date

I have tried the following:
add_months(to_Date('04/01/ind.birth_dte','MM/DD/YYYY'), 864) >= to_date('&StartDt','MM/DD/YYYY')
Is there a better way to pull April first of the participant's 72nd birth date?
You could use an interval calculation instead, but not sure how you're defining 'better'. Assuming you do want April 1st of the year in which their 72 birthday falls:
trunc(ind.birth_dte, 'YYYY') + interval '72-3' year to month
The trunc() function goes to the first day of their birth year, and the interval adds 72 years and 3 months to that, which will be April 1st.
SQL Fiddle with some sample dates, including a leap day to show that isn't a problem.
Or to compare that adjusted date with a fixed date as a filter:
where trunc(ind.birth_dte, 'YYYY') + interval '72-3' year to month
> to_date('&StartDt','MM/DD/YYYY');
SQL Fiddle.
You can use the trunc() method with your version as well to save building up a string and calling to_date, adding an additional three months to the add_months call (though I'd suggest you at least need a comment indicating where '867' comes from):
where add_months(trunc(ind.birth_dte, 'YYYY'), 867)
> to_date('&StartDt','MM/DD/YYYY');