Every month I have to fetch records for the previous month from a Db2 database. How can I write a Db2 query to fetch the last month of data without hard-coding the date range? For example, when run in December 2021, the query would return records dated between '2021-11-01' AND '2021-11-30', and those dates would change dynamically when I run the same query a month later.
It's easy to can precompute the date range in a cte and then use it in the main query. Assuming your table t has a ts column to filter by, you can do:
with
r as (
select
to_date(year(c) || '-' || month(c) || '-01' , 'YYYY-MM-DD') as e,
to_date(year(p) || '-' || month(p) || '-01' , 'YYYY-MM-DD') as b
from (
select current date as c, current date - 1 month as p from sysibm.sysdummy1
) x
)
select *
from t
cross join r
where t.ts >= r.b and t.ts < r.e
See example at db<>fiddle.
There are a few ways to describe the prior month as a date range in a Db2 SQL query. Some datetime SQL functions are not available on Db2 for z/OS, but even then you can still use date arithmetic and the LAST_DAY() function.
First day of last month: LAST_DAY(CURRENT DATE - 2 MONTHS) + 1 DAY
Last day of last month: LAST_DAY(CURRENT DATE - 1 MONTH)
First day of this month: LAST_DAY(CURRENT DATE - 1 MONTH) + 1 DAY
Inclusive-exclusive example (preferred approach):
SELECT ... WHERE someDateTimeColumn >= LAST_DAY(CURRENT DATE - 2 MONTHS) + 1 DAY
AND someDateTimeColumn < LAST_DAY(CURRENT DATE - 1 MONTH) + 1 DAY
Inclusive-inclusive example (calling the DATE() function will prevent implicit type conversion which could skip some some qualifying rows):
SELECT ... WHERE someDateTimeColumn >= LAST_DAY(CURRENT DATE - 2 MONTHS) + 1 DAY
AND DATE(someDateTimeColumn) <= LAST_DAY(CURRENT DATE - 1 MONTH)
If you're querying Db2 for LUW v11.1 or newer, you can also call the THIS_MONTH() function to get the first day of an input month.
First day of last month: THIS_MONTH(CURRENT DATE - 1 MONTH)
First day of this month: THIS_MONTH(CURRENT DATE)
Inclusive-exclusive example:
SELECT ... WHERE someDateTimeColumn >= THIS_MONTH(CURRENT DATE - 1 MONTH)
AND someDateTimeColumn < THIS_MONTH(CURRENT DATE)
Related
I want to get data from last month day by day, I can get the last 30 days but I just want the month as it may be less or more than 30 days,
this is the query for getting the last 30 days
SELECT Trunc(timestamp),
Count(*)
FROM table1
WHERE Trunc(timestamp) > Trunc(sysdate - 30)
GROUP BY Trunc(timestamp)
ORDER BY 1;
Also, I am using it in a shell script if I can make a variable in the script and put it the query
To get data from the start of the current month until today:
SELECT TRUNC(timestamp) AS day,
COUNT(*)
FROM table1
WHERE timestamp >= TRUNC(SYSDATE, 'MM')
AND timestamp < TRUNC(SYSDATE) + INTERVAL '1' DAY
GROUP BY TRUNC(timestamp)
ORDER BY day
To get data from the same day last month until today:
SELECT TRUNC(timestamp) AS day,
COUNT(*)
FROM table1
WHERE timestamp >= ADD_MONTHS(TRUNC(SYSDATE), -1)
AND timestamp < TRUNC(SYSDATE) + INTERVAL '1' DAY
GROUP BY TRUNC(timestamp)
ORDER BY day
db<>fiddle here
I need Dynamic query in BigQuery to find Date of Day Saturday has occurred in First week of Year 2021.
Consider the Day on date of 2022-01-01 is Saturday.
Therefore, I want to extract the date of last Year first week on which the Saturday was occurred.
Try the following:
with sample_dates as (
select date
from unnest(generate_date_array('2022-01-01','2022-12-31')) as date
)
select
date
,(select last_year_date
from unnest(generate_date_array(date_sub(date, INTERVAL 1 YEAR), date-1)) as last_year_date
where extract(week from date) = extract(week from last_year_date)
and extract(dayofweek from date) = extract(dayofweek from last_year_date)
) as last_year_date
from sample_dates
;
Given all of 2022 dates, this provides the same day of week for the same week in the previous year.
For example 2022-01-01 results in 2022-01-02 which is the first Saturday of the first week of last year.
If you're only looking for a single date the main portion would be the generating the appropriate date range with the generate_date_array function and then filtering based on the same week number and dayofweek value.
Use below - should work for any year - just replace 2021 with whatever year you need
select date(2021, 1, 8 - extract(dayofweek from date(2021, 1, 1)))
I think this code can help you!
You can find the first Saturday with a weekly cycle
declare
i number := 0;
date1 date := date '2022-01-01';
d varchar2(20);
begin
while i < 7 loop
SELECT case
when TO_CHAR(date1 + i, 'fmDay') = 'Saturday' then
date1 + i
end "Day"
into d
FROM DUAL;
i := i + 1;
dbms_output.put_line(d);
end loop;
end;
I am trying to create a view in SQL Developer based on this statement:
SELECT * FROM ORDERS WHERE START_DATE > '01-JUL-2020'
The year element of the date needs to set to the year of the current date if the current month is between July and December otherwise it needs to be the previous year.
The statement below returns the required year but I don't know how to incorporate it (or a better alternative) into the statement above:
select
case
when month(sysdate) > 6 then
year(sysdate)
else
year(sysdate)-1
end year
from dual
Thanks
Oracle doesn't have a built-in month function so I'm assuming that is a user-defined function that you've created. Assuming that's the case, it sounds like you want
where start_date > (case when month(sysdate) > 6
then trunc(sysdate,'yyyy') + interval '6' month
else trunc(sysdate,'yyyy') - interval '6' month
end)
Just subtract six months and compare the dates:
SELECT *
FROM ORDERS
WHERE trunc(add_months(sysdate, -6), 'YYYY') = trunc(start_date, 'YYYY')
This compares the year of the date six months ago to the year on the record -- which seems to be the logic you want.
Objective:
I'm trying to update all but the latest HR record within a given week.
I've written the solution below, but as I reviewed oracle date functionality more, I think it won't work..
'ww' would only let me partition on weeks - starting on the weekday JAN 1 occurs.
'iw' would be closer, but the weeks would be split at new year, and there would be a record remaining from the last week of DEC - if the new year starts mid week..
However, I'm just needing all but the latest record - within that week (sun - Sat) updated.
here's what I've attempted so far.. :
UPDATE hr_info.hr_hours
SET expire_date = SYSDATE, deleted = 'Y', update_date = SYSDATE
WHERE (ROWID, compnay_id) IN (SELECT ROWID, compnay_id
FROM (SELECT hrs.*,
ROW_NUMBER ()
OVER (
PARTITION BY emp_nbr,
TO_CHAR (
hrs_effective_date + 1,
'iw'),
TO_CHAR (
hrs_effective_date,
'yy')
ORDER BY
hrs_effective_date DESC)
rown
FROM hr_info.hr_hours hrs
WHERE compnay_id = 3
AND expire_date =
TO_DATE ('12/31/9999',
'mm/dd/yyyy'))
WHERE rown > 1;
COMMIT;
requested example data :
So, in this example, I'm afraid Dec 1 would count as its own week with 'iw'.
I'd just want to keep / not update the 1/4 record for employee 22 and the 1/5 record for employee 33, and the 1/2 record for employee 44.
And, this is just a small snapshot of the data. Records would hypothetically be created on every week - going back years for each employee.
I am thinking something like this:
UPDATE hr_info.hr_hours h
SET expire_date = SYSDATE,
deleted = 'Y',
update_date = SYSDATE
WHERE h.hrs_effective_date < (
SELECT MAX(h2.hrs_effective_date)
FROM hr_info.hr_hours h2
WHERE h2.company_id = h.company_id AND
TRUNC(hr2.hrs_effective_date, 'IW') = TRUNC(hr.hrs_effective_date, 'IW')
);
Week numbering and thus specific dates within them can be represented 'WW' or 'IW' specification but neither serve OP requirements. The 'IW' represents weeks according to the ISO 8601 date specification; 'WW' according to Gregorian week numbering system. (see https://en.wikipedia.org/wiki/ISO_week_date ) The trouble is neither identify weeks in the required Sun-Sat period. So a third option is needed and that is to calculate the necessary weekly periods. The trouble revolves around the 1st week of the any given year, but we easily find the ending data of the 1st period and from there the beginning date as follows: 1) Truncate the date to the year. 2) Backup 1 day. 3) Find the next Saturday. Result is last day of 1st period. 4) Backup 6 days to the first day of 1st period. That becomes:
select next_day(trunc(sysdate,'yyyy')-1,'sat') - 6;
5) We can now calculate any Sat-Sun dates ranges for as many periods as we want.
With that in hand just find the max date within each period and update other rows.
update hr_hours
set deleted='Y'
, update_date = sysdate
, expire_date = sysdate
where 1=1
and expire_date = date '9999-12-31'
and (employee_nbr,hrs_effective_date) not in
(with date_range as (select date '2019-01-04' sdt, date '2019-03-01' edt from dual) -- get full date range
, weeks as (select level-1 wk from dual connect by level <= (select trunc( (edt-sdt)/7)+1 from date_range)) -- calc number of weekly periods
, yr1st as (select next_day(trunc(sdt,'yyyy'), 'Sat') - 6 p1_start from date_range) -- calculate 1st preiod start date
, periods as (select p1_start+(7*wk) period_begin, p1_start+(7*wk)+6 period_end from yr1st, weeks) -- calculate each period start and end date
select employee_nbr, eff_date
from (
select h.employee_nbr,max(h.hrs_effective_date) eff_date,p.period_begin
from hr_hours h
, periods p
where 1 = 1
and h.hrs_effective_date between p.period_begin and p.period_end
group by h.employee_nbr,p.period_begin));
I need to select recods from oracle table for the current calendar week based on a date datatype field. Currently I am doing like this:
select * from my_table where enter_date > sysdate -7
If today is Thursday, this query will select records seven days from today which infiltrates to last week on Thursday. Is there a way to select records for the current calendar week dynamically?
If your week starts on a Monday then:
select ...
from ...
where dates >= trunc(sysdate,'IW')
For alternative definitions of the first day of the week, trunc(sysdate,'W') truncates to the day of the week with which the current month began, and trunc(sysdate,'WW') truncates to the day of the week with which the current year began.
See other available truncations here: http://docs.oracle.com/cd/E11882_01/server.112/e26088/functions255.htm#i1002084
to_char(sysdate, 'd') returns day of week in [1..7] range; so try using
select *
from my_table
where enter_date >= trunc(sysdate) - to_char(sysdate, 'd') + 1
Here is the SQLFiddel Demo
Below is the query which you can try
select Table1.*
from Table1
where dates > sysdate - TO_CHAR(SYSDATE,'D')