Update date column with sysdate based on the interval - sql

I need to create a plsql script that must update the population_date column with sysdate based on the population interval (hourly, daily, weekly, monthly) when executed.
For example, if it is a weekly population interval, the existing date in the population_date column must be updated as follows:
Rec_sid (existing date) Population_date
1 20-jan-2020 sysdate(03-aug-2020)
2 20-jan-2020 sysdate (03-aug-2020)
3 19-jan-2020 sysdate-1(02-aug-2020)
4 19-jan-2020 sysdate-1(02-aug-2020)
5 18-jan-2020 sysdate-2(01-aug-2020)
6 18-jan-2020 sysdate-2(01-aug-2020)
7 17-jan-2020 sysdate-3 (31-jul-2020)
8 17-jan-2020 sysdate-3(31-jul-2020)
9 17-jan-2020 sysdate-3(31-jul-2020)
10 16-jan-2020 sysdate-4(30-jul-2020)
11 16-jan-2020 sysdate-4)30-jul-2020)
12 15-jan-2020 sysdate-5(29-jul-2020)
13 15-jan-2020 sysdate-5(29-jul-2020)
14 14-jan-2020 sysdate-6(28-jul-2020)
And this column exists in 100 tables with different structure and the population_date column alone must be updated with the current date based on the interval.

If I understand correctly, you want the most recent date on the same day of the week on or before today. That logic would be:
population_date + floor( (sysdate - population_date) / 7) * 7
You can put this into an update as:
update t
set population_date = population_date + floor( (sysdate - population_date) / 7) * 7;
I would advise you to run a select first to validate the results.

Related

How do I generate a list of dates of every 7 days between a range of dates based on a date field in Oracle SQL?

I need to generate a list of week end dates based on the first week end date, and between a date range.
For example: I have a week end date of '06/04/2022'. If I enter 06/01/2022-01/01/2023 as my date parameters, I need a list of every seven days beginning on 06/04/2022 through 01/01/2023. The output would look something like this:
Dates
06/04/2022
06/11/2022
06/18/2022
.
.
.
12/24/2022
12/31/2022
Note: the initial week end date is not necessarily always on a Saturday, so it would need to be based on the actual date and not the day of the week.
I have this code which produces every day between two dates, but I need every seven days between two dates, and based on a date field retrieved from another table. I'm stuck on how to get every seven days, or every week from the date.
select (date'2022-06-04' + level - 1) dt
from dual
connect by level <= (date'2023-01-01' - date'2022-06-01' + 1)
Multiply the step size by 7:
SELECT DATE '2022-06-04' + (level - 1) * 7 AS dt
FROM dual
CONNECT BY DATE '2022-06-04' + (level - 1) * 7 <= DATE '2023-01-01'
Or, to make the calculation you are preforming more obvious that you are adding a week, you can use an INTERVAL literal:
SELECT DATE '2022-06-04' + (level - 1) * INTERVAL '7' DAY AS dt
FROM dual
CONNECT BY DATE '2022-06-04' + (level - 1) * INTERVAL '7' DAY <= DATE '2023-01-01'
You could also calculate the number of weeks required in your connect by levels code.
i.e. This would give you the number of rows required
CONNECT BY LEVEL < (DATE2 - DATE1) / 7
Notably the DATE2 - DATE1 code works because Oracle likes to think of things in terms of days. i.e. Sysdate - 1 is just yesterday. Sysdate + 1 is just tomorrow.
Then tack on a + 1 since you probably want to return 1 row in the case it's less than a week
And then doing this
SELECT DATE'2023-01-24' + (LEVEL-1) * 7
FROM DUAL
CONNECT BY LEVEL < ((SYSDATE - DATE'2023-01-24') / 7) + 1

Where Clause on two column sequentially

I want to select query where I can fetch records from a table based 2 column where timestamp value match in both column sequentially.
SELECT *
FROM commerce_order
WHERE CHANGED BETWEEN 1638342000 AND 1641020400
AND created BETWEEN 1638342000 AND 1641020400
Like column changed update 31st at 10 AM and Column created have value 31 at 11AM both should be shown in the result 1 10 AM then next in 11 PM
10 AM
11 AM
So the "created" timestamp should be 1 minute after the "changed" timestamp?
Then you could truncate them on the minute to compare them.
select *
from commerce_order
where changed between unix_timestamp('2021-12-01 07:00') and unix_timestamp('2022-01-01 07:00')
and cast(date_format(from_unixtime(created), '%Y-%m-%d %H:%i') AS datetime) = cast(date_format(from_unixtime(changed), '%Y-%m-%d %H:%i') AS datetime) + interval 1 minute
db<>fiddle here

How can I truncate a timestamp to make readjustments to a date in Oracle?

I have the following query in my SELECT from Oracle:
CASE
WHEN to_char(ola.promise_date, 'D') = 2 THEN (ola.promise_date - 4)
WHEN to_char(ola.promise_date, 'D') = 3 THEN (ola.promise_date - 4)
WHEN to_char(ola.promise_date, 'D') > 3 AND to_char(ola.promise_date, 'D') < 7 THEN (ola.promise_date - 2)
WHEN to_char(ola.promise_date, 'D') = 7 THEN (ola.promise_date - 2)
WHEN to_char(ola.promise_date, 'D') = 1 THEN (ola.promise_date - 2)
END mod_Promise_date
"ola.promise_date" is a column of type TIMESTAMP, and I use the CASE statement in order to adjust the date, considering the day of the week of the original promise date (because of internal considerations of shipment, among other things)
So, for example, something that has a promise date of 2021-11-07 00:00:00.0000000 will have a modified promise date of 2021-11-05 00:00:00.0000000 (considering Sunday as the seventh day)
Now, I run this query with a program made with C#, there I have a date picker in order to select specific promise dates, so the user can choose Sunday, November 7, 2021 and it will run the query as said before, this works good with the exception of promise dates that are something like 2021-11-07 23:59:00.0000000 because the query will consider the date as 8th of November instead of 7th, and this is not expected behavior, because the hour, minutes, seconds and fractional seconds are not really needed in this specific instance of the project.
Is there a way to ignore the hour, minutes, seconds and fractional seconds in the CASE-WHEN statement? Or floor down the date to consider everything in the same day as the day specified, without consideration of the time.
I'm pretty new using Oracle, so sorry if I'm not clear enough or if the query doesn't look viable.
You can use TRUNC(datetime_value) to truncate a DATE or a TIMESTAMP data type and set the time component to midnight:
CASE TRUNC(ola.promise_date) - TRUNC(ola.promise_date, 'IW')
WHEN 0 /* Monday */ THEN TRUNC(ola.promise_date) - 2
WHEN 1 /* Tuesday */ THEN TRUNC(ola.promise_date) - 4
WHEN 2 /* Wednesday */ THEN TRUNC(ola.promise_date) - 4
WHEN 6 /* Sunday */ THEN TRUNC(ola.promise_date) - 2
ELSE TRUNC(ola.promise_date) - 2
END mod_Promise_date
Note: TO_CHAR(datevalue, 'D') will give different values depending on where you are in the world as different territories consider the week to start on different days-of-the-week. If you want a territory-agnostic method of determining the day-of-the-week then you can find the difference from the start of the ISO week using TRUNC(datetime_value) - TRUNC(datetime_value, 'IW').
If I understood you correctly, you'll just have to truncate that value and "remove" time component (i.e. reset it to midnight).
For example:
(just setting format; you don't have to do that)
SQL> alter session set nls_timestamp_format = 'dd.mm.yyyy hh24:mi:ss.ff6';
Session altered.
Query that shows the result:
SQL> select systimestamp,
2 trunc(systimestamp) result
3 from dual;
SYSTIMESTAMP RESULT
----------------------------------- -------------------
05.11.21 19:29:41,207000 +01:00 05.11.2021 00:00:00
SQL>
You'd have
... THEN (trunc(ola.promise_date) - 4)

How to get data for past X days using timestamp column?

I have a below query which gives me data for past 12 hour. Instead of that I wanted to get data for past X days which should be configurable if possible? Is there any way to do it?
SELECT processId,
houroftheday,
minuteofhour,
listagg(clientId, ',') within group (order by minuteofhour) as clientIds,
count(*) as psg
FROM data.process
where kite = 'BULLS'
and code is null
and timestampinepochsecond > date_part(epoch, sysdate) - 3600 * 12
group by 1, 2, 3
How can I use timestampinepochsecond column to get data for past X days?
The passed N days would be:
timestampinepochsecond > date_part(epoch, sysdate) - N*24*60*60

Filter date with intervals of 1 hour between two random dates in the same day

The rule
Any records between one hour should be counted as one.
Data
ID DATE
1 06/07/2017 09:20:35
2 06/07/2017 10:20:35
3 06/07/2017 10:25:30
4 06/07/2017 10:40:35
5 06/07/2017 10:50:35
6 06/07/2017 11:25:30
7 06/07/2017 11:50:20
8 06/07/2017 15:25:30
9 06/07/2017 17:25:30
10 06/07/2017 17:30:30
11 06/07/2017 17:40:55
Expected result
count date
5 06/07/2017
Why? Based on the minimum date, the records between one hour after are counted as one. Something like this:
count range_date
1 09:20:35 - 10:20:35
1 10:20:36 - 11:20:36
1 11:20:37 - 12:20:37
0 12:20:38 - 13:20:38
0 13:20:39 - 14:20:39
0 14:20:40 - 15:20:40
1 15:20:41 - 16:20:41
1 17:20:42 - 18:20:42
Any suggestions to do so?
Something in one statment since I don't have a rule for the dates (min/max). I just know that all dates it's on the same day.
And I dont want to make N selects between every hour...
If I correctly understood your problem, this is a query that obtain the result you're looking for:
SELECT
TRUNC(dt) AS day,
COUNT(DISTINCT TRUNC(dt - 20 / (24 * 60) - (35 + TO_NUMBER(TO_CHAR(dt, 'HH24')) - 9) / (24 * 60 * 60), 'HH24')) AS hours
FROM yourtable
GROUP BY TRUNC(dt)
TRUNC(dt, 'HH24') truncates the date to hour (minutes and seconds
are set to 0)
I subtract the minutes and seconds of starting hour to
"shift" the TRUNC to correct time period
TO_NUMBER(TO_CHAR(dt, 'HH24')) - 9) is mandatory to add one second for every hour
With COUNT DISTINCT you
count the number of different hours.
If the initial hour is variable (as I suppose) I think the easiest way is to keep it with separate query, extract hour, minute and second and use them as variables in input to the main query
You want to count the number of hours since the earliest date/time for each record. Here is one approach:
select trunc(dt), count(distinct trunc((dt - min_dt) / 24)) as num_hours
from (select t.*, min(dt) over (partition by trunc(dt) order by dt) as min_dt
from t
) t
group by trunc(dt);
This expression (dt - min_dt) / 24 calculates the time between each date/time and the earlier in hours. the count(distinct) counts the number of distinct hours seen in the date.