Get data of last Month day by day in oracle sql - sql

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

Related

Bring data from the last day of the previous month beyond

I'm using Oracle SQL Developer and I would like to make a SELECT that brings all the products sold from the last day of the previous month (but only products sold from 4 pm on the last day of the previous month) to the current day (only until 8 am of the current day).
For example, today is 7/21/2022. If I run this query today, it should bring data from:
06/30/2022 above 16:00hrs -> 07/21/2022 until 08:00hrs
You can use TRUNC(value, 'MM') to find midnight of the 1st day of the current month and then subtract 8 hours to find the start of the range and then use TRUNC(value) to find midnight of today and add 8 hours to find the end of the range:
SELECT *
FROM table_name
WHERE date_column >= TRUNC(SYSDATE, 'MM') - INTERVAL '8' HOUR
AND date_column <= TRUNC(SYSDATE) + INTERVAL '8' HOUR;
You can use TRUNC to get to the first day of a date's month. Then subtract one day and add sixteen hours. And it's again TRUNC that you use to get back to the beginning of a day (midnight) to which you can add eight hours.
select *
from mytable
where dt >= trunc(sysdate, 'mm') - interval '1' day + interval '16' hour
and dt < trunc(sysdate, 'dd') + interval '8' hour
order by dt;

How can I aggregate time series data in postgres from a specific timestamp & fixed intervals (e.g. 1 hour , 1 day, 7 day ) without using date_trunc()?

I have a postgres table "Generation" with half-hourly timestamps spanning 2009 - present with energy data:
I need to aggregate (average) the data across different intervals from specific timepoints, for example data from 2021-01-07T00:00:00.000Z for one year at 7 day intervals, or 3 months at 1 day interval or 7 days at 1h interval etc. date_trunc() partly solves this, but rounds the weeks to the nearest monday e.g.
SELECT date_trunc('week', "DATETIME") AS week,
count(*),
AVG("GAS") AS gas,
AVG("COAL") AS coal
FROM "Generation"
WHERE "DATETIME" >= '2021-01-07T00:00:00.000Z' AND "DATETIME" <= '2022-01-06T23:59:59.999Z'
GROUP BY week
ORDER BY week ASC
;
returns the first time series interval as 2021-01-04 with an incorrect count:
week count gas coal
"2021-01-04 00:00:00" 192 18291.34375 2321.4427083333335
"2021-01-11 00:00:00" 336 14477.407738095239 2027.547619047619
"2021-01-18 00:00:00" 336 13947.044642857143 1152.047619047619
****EDIT: the following will return the correct weekly intervals by checking the start date relative to the nearest monday / start of week, and adjusts the results accordingly:
WITH vars1 AS (
SELECT '2021-01-07T00:00:00.000Z'::timestamp as start_time,
'2021-01-28T00:00:00.000Z'::timestamp as end_time
),
vars2 AS (
SELECT
((select start_time from vars1)::date - (date_trunc('week', (select start_time from vars1)::timestamp))::date) as diff
)
SELECT date_trunc('week', "DATETIME" - ((select diff from vars2) || ' day')::interval)::date + ((select diff from vars2) || ' day')::interval AS week,
count(*),
AVG("GAS") AS gas,
AVG("COAL") AS coal
FROM "Generation"
WHERE "DATETIME" >= (select start_time from vars1) AND "DATETIME" < (select end_time from vars1)
GROUP BY week
ORDER BY week ASC
returns..
week count gas coal
"2021-01-07 00:00:00" 336 17242.752976190477 2293.8541666666665
"2021-01-14 00:00:00" 336 13481.497023809523 1483.0565476190477
"2021-01-21 00:00:00" 336 15278.854166666666 1592.7916666666667
And then for any daily or hourly (swap out day with hour) intervals you can use the following:
SELECT date_trunc('day', "DATETIME") AS day,
count(*),
AVG("GAS") AS gas,
AVG("COAL") AS coal
FROM "Generation"
WHERE "DATETIME" >= '2022-01-07T00:00:00.000Z' AND "DATETIME" < '2022-01-10T23:59:59.999Z'
GROUP BY day
ORDER BY day ASC
;
In order to select the complete week, you should change the WHERe-clause to something like:
WHERE "DATETIME" >= date_trunc('week','2021-01-07T00:00:00.000Z'::timestamp)
AND "DATETIME" < (date_trunc('week','2022-01-06T23:59:59.999Z'::timestamp) + interval '7' day)::date
This will effectively get the records from January 4,2021 until (and including ) January 9,2022
Note: I changed <= to < to stop the end-date being included!
EDIT:
when you want your weeks to start on January 7, you can always group by:
(date_part('day',(d-'2021-01-07'))::int-(date_part('day',(d-'2021-01-07'))::int % 7))/7
(where d is the column containing the datetime-value.)
see: dbfiddle
EDIT:
This will get the list from a given date, and a specified interval.
see DBFIFFLE
WITH vars AS (
SELECT
'2021-01-07T00:00:00.000Z'::timestamp AS qstart,
'2022-01-06T23:59:59.999Z'::timestamp AS qend,
7 as qint,
INTERVAL '1 DAY' as qinterval
)
SELECT
(select date(qstart) FROM vars) + (SELECT qinterval from vars) * ((date_part('day',("DATETIME"-(select date(qstart) FROM vars)))::int-(date_part('day',("DATETIME"-(select date(qstart) FROM vars)))::int % (SELECT qint FROM vars)))::int) AS week,
count(*),
AVG("GAS") AS gas,
AVG("COAL") AS coal
FROM "Generation"
WHERE "DATETIME" >= (SELECT qstart FROM vars) AND "DATETIME" <= (SELECT qend FROM vars)
GROUP BY week
ORDER BY week
;
I added the WITH vars to do the variable stuff on top and no need to mess with the rest of the query. (Idea borrowed here)
I only tested with qint=7,qinterval='1 DAY' and qint=14,qinterval='1 DAY' (but others values should work too...)
Using the function EXTRACT you may calculate the difference in days, weeks and hours between your timestamp ts and the start_date as follows
Difference in Days
extract (day from ts - start_date)
Difference in Weeks
Is the difference in day divided by 7 and truncated
trunc(extract (day from ts - start_date)/7)
Difference in Hours
Is the difference in day times 24 + the difference in hours of the day
extract (day from ts - start_date)*24 + extract (hour from ts - start_date)
The difference can be used in GROUP BY directly. E.g. for week grouping the first group is difference 0, i.e. same week, the next group with difference 1, the next week, etc.
Sample Example
I'm using a CTE for the start date to avoid multpile copies of the paramater
with start_time as
(select DATE'2021-01-07' as start_ts),
prep as (
select
ts,
extract (day from ts - (select start_ts from start_time)) day_diff,
trunc(extract (day from ts - (select start_ts from start_time))/7) week_diff,
extract (day from ts - (select start_ts from start_time)) *24 + extract (hour from ts - (select start_ts from start_time)) hour_diff,
value
from test_table
where ts >= (select start_ts from start_time)
)
select week_diff, avg(value)
from prep
group by week_diff order by 1

Select rows where max date is less than December 31st of the previous year

I am using Oracle SQL developer. I am trying to select rows where max date is less than December 31st of the previous year. I tried this query below but kept getting an error.
Select ORG_ID, STS_DTE
from Table1
Group By RC_ORG_ID
Having MAX(STS_DTE)< '31-Dec-' || extract (year from SYSDATE-1)
I would use trunc():
having MAX(STS_DTE) < trunc(sysdate, 'YYYY') - interval '1 day'
I'm not sure if you want sysdate - interval '1' day.

Group by week and consider Saturday as start day of the week

I want to query my postgresql data and group the results by week, so I'm using the following query:
select
date_trunc ('week', date_column) as week,
sum (orders) as orders_count
from database
group by week
But it uses Monday as start day of the week, while I want my weeks to be like 'Saturday -> Friday'. How can I acheive this?
Just subtract two days, and you land on saturday:
select
date_trunc('week', date_column)::date - 2 as week,
sum (orders) as orders_count
from the_table
group by week
You can just offset by two days, as follows:
select
date_trunc ('week', date_column + interval '2 days') - interval '2 days' as week,
sum (orders) as orders_count
from database
group by week

Select Data From Multiple Days Between Certain Times (Spanning 2 days)

I need to know how many entries appear in my DB for the past 7 days with a timestamp between 23:00 & 01:00...
The Issue I have is the timestamp goes across 2 days and unsure if this is even possible in the one query.
So far I have come up with the below:
select trunc(timestamp) as DTE, extract(hour from timestamp) as HR, count(COLUMN) as Total
from TABLE
where trunc(timestamp) >= '12-NOV-19' and
extract(hour from timestamp) in ('23','00','01')
group by trunc(timestamp), extract(hour from timestamp)
order by 1,2 desc;
The result I am hoping for is something like this:
DTE | Total
20-NOV-19 5
19-NOV-19 4
18-NOV-19 4
17-NOV-19 6
Many thanks
Filter on the day first comparing it to TRUNC( SYSDATE ) - INTERVAL '7' DAY and then consider the hours by comparing the timestamp to itself truncated back to midnight with an offset of a number of hours.
select trunc(timestamp) as DTE,
extract(hour from timestamp) as HR,
count(COLUMN) as Total
from TABLE
WHERE timestamp >= TRUNC( SYSDATE ) - INTERVAL '7' DAY
AND ( timestamp <= TRUNC( timestamp ) + INTERVAL '01:00' HOUR TO MINUTE
OR timestamp >= TRUNC( timestamp ) + INTERVAL '23:00' HOUR TO MINUTE
)
group by trunc(timestamp), extract(hour from timestamp)
order by DTE, HR desc;
Subtract or add an hour to derive the date. I'm not sure what date you want to assign to each period, but the idea is:
select trunc(timestamp - interval '1' hour) as DTE,
count(*) as Total
from t
where trunc(timestamp - interval '1' hour) >= DATE '2019-11-12' and
extract(hour from timestamp) in (23, 0)
group by trunc(timestamp - interval '1' hour)
order by 1 desc;
Note: If you want times between 11:00 p.m. and 1:00 a.m., then you want the hour to be 23 or 0.