Running query against quarter or week of the year - sql

I have this query that works for 1 quarter. However, what if I want to do the same query but for 2nd, 3rd, and 4th quarter of the calendar year or even WEEKLY?
How can I do the same query without having to manually change the values defining the quarter or week of the year?
SELECT count(1), AVG(resolved_at::TIMESTAMP - created_at::TIMESTAMP)
FROM supp_cases
WHERE created_at::TIMESTAMP >= '2017-01-01 00:00:00'::TIMESTAMP
AND resolved_at::TIMESTAMP <= '2017-03-31 23:59:59'::TIMESTAMP;
Q1 = 2017-01-01 00:00:00 TO 2017-03-31 23:59:59
Q2 = 2017-04-01 00:00:00 TO 2017-06-30 23:59:59
Q3 = 2017-07-01 00:00:00 TO 2017-09-30 23:59:59
Q4 = 2017-10-01 00:00:00 TO 2017-12-31 23:59:59

How about this?
SELECT TO_CHAR(created_at, 'YYYY-Q') as created_at_yyyyq,
TO_CHAR(resolved_at, 'YYYY-Q') as resolved_at_yyyyq,
count(*)
FROM supp_cases
GROUP BY created_at_yyyyq, resolved_at_yyyyq
ORDER BY created_at_yyyyq, resolved_at_yyyyq;
If you really want rows created and resolved in the same quarter, you can add:
WHERE TO_CHAR(created_at, 'YYYY-Q') = TO_CHAR(resolved_at, 'YYYY-Q')

You might try using intervals, e.g.:
SELECT * FROM example WHERE created_at > '2017-01-01'
AND resolved_at < (DATE('2017-01-01') + INTERVAL '1 WEEKS');
SELECT * FROM example WHERE created_at > '2017-01-01'
AND resolved_at < (DATE('2017-01-01') + INTERVAL '2 MONTHS');

Related

Recover all weeks of a month in Oracle SQL

I would like to build a SQL statement to automatically retrieve information about all the weeks of a month.
For example, for the month of February 2023:
Retrieve the first week (Monday to Sunday): 30/01/2023 - 05/01/2023
...
Retrieve the last week :
27/02/2023 - 05/03/2023.
Thanks in advance!
Use a row-generator to generate a list of weeks for the month:
WITH input (month) AS (
SELECT DATE '2023-02-01' FROM DUAL
),
calendar (week_start) AS (
SELECT TRUNC(TRUNC(month, 'MM'), 'IW') + 7 * (LEVEL - 1)
FROM input
CONNECT BY TRUNC(TRUNC(month, 'MM'), 'IW') + 7 * (LEVEL - 1)
< ADD_MONTHS(TRUNC(month, 'MM'), 1)
)
SELECT week_start,
week_start + INTERVAL '6 23:59:59' DAY TO SECOND AS week_end
FROM calendar
Which outputs:
WEEK_START
WEEK_END
2023-01-30 00:00:00
2023-02-05 23:59:59
2023-02-06 00:00:00
2023-02-12 23:59:59
2023-02-13 00:00:00
2023-02-19 23:59:59
2023-02-20 00:00:00
2023-02-26 23:59:59
2023-02-27 00:00:00
2023-03-05 23:59:59
fiddle

How to display in sql records of past Month (not last 30 days) and update them every 2nd calendar date of the next month?

I am trying to represent data for the past MONTH so for example 30 days from April 2nd and continue to update data every month so that on May 2nd, data shows for the 30 days prior to May 2nd.
I will show my current code:
SELECT 'Working Equipment' label, count(*) FROM LOGS_HISTORY
WHERE MODE__ = 'Working'
AND TIME_ >= add_months(sysdate, -1)
union all
SELECT 'Standby Equipment' label, count(distinct TAG_IDENTIFIER) FROM LOGS_HISTORY
WHERE MODE__ = 'Standby'
AND TIME_ >= add_months(sysdate, -1)
It shows data 30 days prior to sysdate, please look through it and advise what should I change?
For your requirement you can use this:
AND TIME_ >= add_months(trunc(sysdate-1,'MM'),-1)
This example query shows how the start date changes from 1st March to 1st April on 2nd May:
with dates as
( select trunc(date '2022-04-27')+rownum d
from dual
connect by level < 10
)
select d as sys_date, add_months(trunc(d-1,'MM'),-1) from_date
from dates
order by 1;
Result:
SYS_DATE FROM_DATE
-------- ---------
28-APR-2022 00:00:00 01-MAR-2022 00:00:00
29-APR-2022 00:00:00 01-MAR-2022 00:00:00
30-APR-2022 00:00:00 01-MAR-2022 00:00:00
01-MAY-2022 00:00:00 01-MAR-2022 00:00:00
02-MAY-2022 00:00:00 01-APR-2022 00:00:00
03-MAY-2022 00:00:00 01-APR-2022 00:00:00
04-MAY-2022 00:00:00 01-APR-2022 00:00:00
05-MAY-2022 00:00:00 01-APR-2022 00:00:00
06-MAY-2022 00:00:00 01-APR-2022 00:00:00

How to fill the time gap after grouping date record for months in postgres

I have table records as -
date n_count
2020-02-19 00:00:00 4
2020-07-14 00:00:00 1
2020-07-17 00:00:00 1
2020-07-30 00:00:00 2
2020-08-03 00:00:00 1
2020-08-04 00:00:00 2
2020-08-25 00:00:00 2
2020-09-23 00:00:00 2
2020-09-30 00:00:00 3
2020-10-01 00:00:00 11
2020-10-05 00:00:00 12
2020-10-19 00:00:00 1
2020-10-20 00:00:00 1
2020-10-22 00:00:00 1
2020-11-02 00:00:00 376
2020-11-04 00:00:00 72
2020-11-11 00:00:00 1
I want to be grouped all the records into months for finding month total count which is working, but there is a missing of month. how to fill this gap.
time month_count
"2020-02-01" 4
"2020-07-01" 4
"2020-08-01" 5
"2020-09-01" 5
"2020-10-01" 26
"2020-11-01" 449
This is what I have tried.
SELECT (date_trunc('month', date))::date AS time,
sum(n_count) as month_count
FROM table1
group by time
order by time asc
You can use generate_series() to generate all starts of months between the earliest and latest date available in the table, then bring the table with a left join:
select d.dt, coalesce(sum(t.n_count), 0) as month_count
from (
select generate_series(date_trunc('month', min(date)), date_trunc('month', max(date)), '1 month') as dt
from table1
) as d(dt)
left join table1 t on t.date >= d.dt and t.date < d.dt + interval '1 month'
group by d.dt
order by d.dt
I would simply UNION a date series, generated from MIN and MAX date:
demo:db<>fiddle
WITH cte AS ( -- 1
SELECT
*,
date_trunc('month', date)::date AS time
FROM
t
)
SELECT
time,
SUM(n_count) as month_count --3
FROM (
SELECT
time,
n_count
FROM cte
UNION
SELECT -- 2
generate_series(
(SELECT MIN(time) FROM cte),
(SELECT MAX(time) FROM cte),
interval '1 month'
)::date,
0
) s
GROUP BY time
ORDER BY time
Use CTE to calculate date_trunc only once. Could be left out if you like to call your table twice in the UNION below
Generate monthly date series from MIN to MAX date containing your n_count value = 0. Add it to the table
Do your calculation

Filter By date with format 'dd/mm'

I have difficulty in syntax query dbms oracle for filtering by date, but i just want filter by date with format (dd/mm). and my data database record is (dd/mm/yyyy). How query to filter by date mm/dd
tablename.fieldname >= '01/01'
with s as (
select date '2019-01-01' + level * 15 dt from dual connect by level <= 20)
select s.*
from s
where to_number(to_char(dt, 'mmdd')) > 0501;
DT
-------------------
2019-05-16 00:00:00
2019-05-31 00:00:00
2019-06-15 00:00:00
2019-06-30 00:00:00
2019-07-15 00:00:00
2019-07-30 00:00:00
2019-08-14 00:00:00
2019-08-29 00:00:00
2019-09-13 00:00:00
2019-09-28 00:00:00
2019-10-13 00:00:00
2019-10-28 00:00:00
12 rows selected.
Have you tried something like this? Though it's not exactly the format you wanted
SELECT * from yourTableName
WHERE EXTRACT(month from yourDateColumn) >= '1'
AND EXTRACT(day from yourDateColumn) >= '1';
Oracle EXTRACT documentaion
Possible related questions:
Compare only day and month with date field in mysql
SQL Filter Out Specific Month, Day, and Time for Any Year

How to get Month, Year and Days in postgresql between two dates

I have two columns in the sql table which is startdate and enddate
Startdate Enddate
27-12-2015 22:30 03-01-2016 19:30
01-01-2016 12:45 09-02-2016 18:30
I want to get the resultant table like
Startdate Enddate Month year days
27-12-2015 22:30 03-01-2016 19:30 Dec 2015 5
27-12-2015 22:30 03-01-2016 19:30 Jan 2016 3
01-01-2016 12:45 09-02-2016 18:30 Jan 2016 31
01-01-2016 12:45 09-02-2016 18:30 Feb 2016 9
A rough solution would be to generate all the days and then aggregate (count) them. It works, but it's rough on memory. If it's not crucial, this solution would definitely work. The alternative is to generate a months series and make a day diff with a lot of conditions, if performance is critical.
SELECT
dates.startdate::DATE,
dates.enddate::DATE,
to_char(days.s, 'Mon') AS mon,
to_char(days.s, 'YYYY') AS yr,
count(1) AS d
FROM dates
CROSS JOIN LATERAL (
SELECT * FROM generate_series(dates.startdate, dates.enddate, INTERVAL '1 day') s
) days
GROUP BY 1, 2, 3, 4
In any case, here is the second variant, that loops through months instead (faster, harder to understand):
SELECT
dates.startdate::DATE,
dates.enddate::DATE,
to_char(months.startdate, 'Mon') AS mon,
to_char(months.startdate, 'YYYY') AS yr,
least(
months.enddate::DATE - dates.startdate::DATE + 1, -- takes care of first month
dates.enddate::DATE - months.startdate::DATE + 1, -- takes care of last month
months.enddate::DATE - months.startdate::DATE + 1 -- takes care of full months from the middle of the intervals
) AS "days"
FROM dates
-- get months as first day in that month
CROSS JOIN LATERAL (
SELECT * FROM generate_series(
(to_char(dates.startdate, 'YYYY-MM-') || '01')::DATE,
(to_char(dates.enddate + INTERVAL '1 month', 'YYYY-MM-') || '01')::DATE - 1, INTERVAL '1 month') m
) days
-- get months as start date and end date
CROSS JOIN LATERAL (
SELECT
days.m::DATE AS startdate,
(days.m + INTERVAL '1 month')::DATE - 1 AS enddate
) months
In this particular case a plpgsql function can provide better performance than a plain sql query.
create or replace function get_months(startdate date, enddate date)
returns table (mon text, year int, days int)
language plpgsql as $$
declare d date;
begin
d:= date_trunc('month', startdate);
while d < enddate loop
mon:= to_char(d, 'Mon');
year:= to_char(d, 'YYYY');
days:= case
when d+ '1month'::interval > enddate then enddate- d+ 1
when d < startdate then (d+ '1month'::interval)::date- startdate
else (d+ '1month'::interval)::date- d
end;
return next;
d:= d+ '1month'::interval;
end loop;
end
$$;
Test:
with my_table(startdate, enddate) as (
values
('2015-12-27 22:30', '2016-01-03 19:30'),
('2016-01-01 12:45', '2016-02-09 18:30')
)
select *
from my_table,
lateral get_months(startdate::date, enddate::date)
startdate | enddate | mon | year | days
------------------+------------------+-----+------+------
2015-12-27 22:30 | 2016-01-03 19:30 | Dec | 2015 | 5
2015-12-27 22:30 | 2016-01-03 19:30 | Jan | 2016 | 3
2016-01-01 12:45 | 2016-02-09 18:30 | Jan | 2016 | 31
2016-01-01 12:45 | 2016-02-09 18:30 | Feb | 2016 | 9
(4 rows)