Date filtering from past two weeks - sql

I have an SQL query where I'm trying to select only records from the past two weeks of the present day i.e. using the 'created_on' column. Any ideas how that is done? I know I can't use specific dates because present day is always changing.
select un.id
, t.type_name as type
, un.content_id
, un.app_link
, un.notification_text
, t.id as type_id
, un.seen_yn,un.created_on
, to_char(un.created_on,'YYYY-MM-DD: HH24:MI') as timestamp
from app.user_notifications as un
left join ref.types as t on t.id = un.notification_type
where un.active_yn = true
and un.user_id = 1
and un.seen_yn = false order by un.created_on desc

You can compare the created_on column with an expression that calculates "two weeks before today":
un.created_on >= current_date - interval '2 weeks'
alternatively you can also subtract 14 days
un.created_on >= current_date - 14

Add yet another condition, e.g.
... and un.created_on >= trunc(sysdate) - 14
In Oracle, when you subtract number from a DATE datatype value, you subtract that many days so - subtracting 14 is two weeks back.
SQL> select sysdate right_now,
2 trunc(sysdate) today_midnight,
3 trunc(sysdate) - 14 two_weeks_back
4 from dual;
RIGHT_NOW TODAY_MIDNIGHT TWO_WEEKS_BACK
------------------- ------------------- -------------------
22.03.2022 07:12:54 22.03.2022 00:00:00 08.03.2022 00:00:00
SQL>
Alternatively, if you prefer interval (which actually says what you're doing), then
SQL> select trunc(sysdate) - interval '14' day from dual;
TRUNC(SYSDATE)-INTE
-------------------
08.03.2022 00:00:00
SQL>

Related

Obtain data from Friday, Saturday and Sunday if today is Monday SQL Oracle

I am looking to obtain all data in a table from yesterday in SQL Oracle.
This is simply enough using the WHERE clause, i.e,
SELECT *
FROM My_Data
WHERE TO_DATE(My_Data.Date,'YYYY-MM-DD') = TRUNC(SYSDATE)-1
However if I now need to add more logic where if the day of the query is a Monday (SYSDATE) then obtain data between Friday and Sunday.
Using a between statement is no issue, I'm just not sure if I can include in a where statement given I'm unable to use case statement here.
Thanks
SELECT
*
FROM
My_Data
WHERE
TO_DATE(My_Data.Date,'YYYY-MM-DD')
Between Case When To_Char(SYSDATE, 'DY') = 'MON' Then TRUNC(SYSDATE)-3 ELSE TRUNC(SYSDATE)-1 END
And TRUNC(SYSDATE)-1
You can use the Case expression in Where clause. Regards...
Don't use TO_DATE on a column that is already a date (and if it is a string then don't store dates as strings).
So you are not dependent on the date language session parameter, you can compare the date to the start of the ISO week (which is independent of language) and you can compare on a date range so that Oracle can use an index on your date column:
SELECT *
FROM My_Data
WHERE "DATE" < TRUNC(SYSDATE)
AND "DATE" >= CASE TRUNC(SYSDATE) - TRUNC(SYSDATE, 'IW')
WHEN 0 -- Monday
THEN TRUNC(SYSDATE) - 3
ELSE TRUNC(SYSDATE) - 1
END;
or:
SELECT *
FROM My_Data
WHERE "DATE" < TRUNC(SYSDATE)
AND ( ( TRUNC(SYSDATE) - TRUNC(SYSDATE, 'IW') = 0 AND "DATE" >= TRUNC(SYSDATE) - 3 )
OR "DATE" >= TRUNC(SYSDATE) - 1
);

Search Last 7 days excluding today Oracle SQL

I have the below code to which I want to return the last 7 days excluding today (for example from 5th May - 11th May as opposed to 5th May - 12th May)
What else would I be able to include to acheive this?
SELECT *
FROM TABLE_1
WHERE DATE_TIME >= SYSDATE -7
You want to have a range that starts from 7 days before midnight today and ends before midnight today:
SELECT *
FROM table_name
WHERE date_time >= TRUNC(sysdate) - 7
AND date_time < TRUNC(sysdate);
This should work:
SELECT *
FROM TABLE_1
WHERE DATE_TIME >= SYSDATE -7
AND TRUNC(DATE_TIME) != TRUNC(SYSDATE)
The TRUNC is needed to strip the time portion of the date column and sysdate.
Note that DATE_TIME >= SYSDATE -7 will include the time portion of SYSDATE and substract 7 days. If you run the query at 10AM, do you want to include rows that have date_time = sysdate - 7 at 9AM too ? If so it is better to add a TRUNC there too DATE_TIME >= TRUNC(SYSDATE) -7.

oracle sql sysdate

All,
I have a sql which is like below used in informatica lookup sql.
select * from table where load_dt = trunc(sysdate) when the time is 2 am to 00.00 am
when time is between nextday 00.30am to 2.00 am, the same sql should read as
select * from table where load_dt = trunc(sysdate-1)
how can i make these two sql in single sql?
is it possible?
thanks
I'm not sure I fully understand the question but I'm assuming that if the hour is less than 2 am you want to subtract 1 from sysdate otherwise keep current sysdate.
You said; 2 am to 00.00 am and 00.30am to 2.00 am... but I interpreted it as above.
Select *
from table
where load_Dt = trunc(sysdate - case
when TO_CHAR(SYSTIMESTAMP,'HH24') < 2 then 1 else 0 end)
or
Select *
from table
where load_Dt = trunc(sysdate - case
when EXTRACT(HOUR FROM SYSTIMESTAMP) < 2 then 1 else 0 end
Depending if Timezone offset is needed or not.
You can just subtract two hours before truncating the date:
select *
from table
where load_dt = trunc(sysdate - 2/24.0) ;
Oracle also supports - interval '2' hour, but I'm old-fashioned sometimes.

Count full months between two dates

I've been working on this for a few hours with no luck and have hit a wall. My data looks like this:
Date1 Date2
2012-05-06 2012-05-05
2012-03-20 2012-01-05
What I'm trying to do is add 1 to the count for every month between two dates. So my output would ideally look like this:
Year Month Sum
2012 2 1
In other words, it should check for "empty" months between two dates and add 1 to them.
This is the code I've worked out so far. It will basically count the number of months between the two dates and group them into months and years.
SELECT
EXTRACT(YEAR FROM Date2::date) as "Year",
EXTRACT(MONTH FROM Date2::date) as "Month",
SUM(DATE_PART('year', Date1::date) - DATE_PART('year', Date2::date)) * 12 +
(DATE_PART('month', Date1::date) - DATE_PART('month', Date2::date))
FROM
test
GROUP BY
"Year",
"Month",
ORDER BY
"Year" DESC,
"Month" DESC;
This is where I'm stuck - I don't know how to actually add 1 for each of the "empty" months.
Test setup
With some sample rows (should be provided in the question):
CREATE TABLE test (
test_id serial PRIMARY KEY
, date1 date NOT NULL
, date2 date NOT NULL
);
INSERT INTO test(date1, date2)
VALUES
('2012-03-20', '2012-01-05') -- 2012-02 lies in between
, ('2012-01-20', '2012-03-05') -- 2012-02 (reversed)
, ('2012-05-06', '2012-05-05') -- nothing
, ('2012-05-01', '2012-06-30') -- still nothing
, ('2012-08-20', '2012-11-05') -- 2012-09 - 2012-10
, ('2012-11-20', '2013-03-05') -- 2012-12 - 2013-02
;
Postgres 9.3 or newer
Use a LATERAL join:
SELECT to_char(mon, 'YYYY') AS year
, to_char(mon, 'MM') AS month
, count(*) AS ct
FROM (
SELECT date_trunc('mon', least(date1, date2)::timestamp) + interval '1 mon' AS d1
, date_trunc('mon', greatest(date1, date2)::timestamp) - interval '1 mon' AS d2
FROM test
) sub1
, generate_series(d1, d2, interval '1 month') mon -- implicit CROSS JOIN LATERAL
WHERE d2 >= d1 -- exclude ranges without gap right away
GROUP BY mon
ORDER BY mon;
What is the difference between LATERAL and a subquery in PostgreSQL?
Postgres 9.2 or older
No LATERAL, yet. Use a subquery instead:
SELECT to_char(mon, 'YYYY') AS year
, to_char(mon, 'MM') AS month
, count(*) AS ct
FROM (
SELECT generate_series(d1, d2, interval '1 month') AS mon
FROM (
SELECT date_trunc('mon', least(date1, date2)::timestamp) + interval '1 mon' AS d1
, date_trunc('mon', greatest(date1, date2)::timestamp) - interval '1 mon' AS d2
FROM test
) sub1
WHERE d2 >= d1 -- exclude ranges without gap right away
) sub2
GROUP BY mon
ORDER BY mon;
Result
year | month | ct
------+-------+----
2012 | 2 | 2
2012 | 9 | 1
2012 | 10 | 1
2012 | 12 | 1
2013 | 1 | 1
2013 | 2 | 1
db<>fiddle here
SQL Fiddle.
Explanation
You are looking for complete calendar months between the two dates.
These queries work with any dates or timestamps in ascending or descending order and should perform well.
The WHERE clause is optional, since generate_series() returns no row if start > end. But it should be a bit faster to exclude empty ranges a priori.
The cast to timestamp makes it a bit cleaner and faster. Rationale:
Generating time series between two dates in PostgreSQL
AFAIK you can simply substract/add dates in postgresql
'2001-06-27 14:43:21'::DATETIME - '2001-06-27 14:33:21'::DATETIME = '00:10:00'::INTERVAL
So in your case that request part should look like
DATE_PART('month', Date1::datetime - Date2::datetime) as "MonthInterval"
age(timestamp1, timestamp2) => returns interval
the we try to extract year and month out of the interval and add them accordingly.
select extract(year from age(timestamp1, timestamp2))*12 + extract(month from
age(timestamp1, timestamp2))

Oracle SQL Where Clause against a date column

I have a DATE column with a date in it but I need to query it to find records less than 30 days old.
START_DATE
----------
01-AUG-2010
09-AUG-2010
22-AUG-2010
09-SEP-2010
Query:
SELECT START_DATE
WHERE START_DATE < 30;
I know it is simple Query in ORACLE SQL but i am doing something wrong.
Use:
SELECT t.start_date
FROM YOUR_TABLE t
WHERE t.start_date > SYSDATE - 30
SYSDATE is Oracle's syntax to get the current date and time
In Oracle, you can do date arithmetic in the context of days, so SYSDATE - 30 means "current date, subtract thirty days" to get a date that is thirty days in the past
If you want to evaluate the date based on thirty days as of midnight, use the TRUNC function:
SELECT t.start_date
FROM YOUR_TABLE t
WHERE t.start_date > TRUNC(SYSDATE) - 30
Don't run TRUNC on the column - that will render an index on the column useless, ensuring a table scan.
SELECT t.start_date
FROM YOUR_TABLE t
WHERE t.start_date > SYSDATE - INTERVAL '30' DAY;
INTERVAL is more portable than assuming that you can add or subtract days, although I've noticed some slight differences in the INTERVAL syntax between Oracle and PostgreSQL.
WHERE START_DATE > SYSDATE - 1
or perhaps
WHERE TRIM(STARTDATE) > TRIM(SYSDATE) - 1