Postgres - how to displays data for the previous year? - sql

I have sql
select
name,
tanggal,
status
from
tbl_person
where
status = 'PROSES'
and date_part('year', tanggal) = 2021 - INTERVAL '1 YEAR'
tanggal is date 2021-01-01
I want to display previous year's data for example in 2020, how to write the correct query?

Using your method:
where status = 'PROSES' and
date_trunc('year', tanggal) = date_trunc('year', current_date) - interval '1 year'
However, I prefer to avoid functions on the column -- so the query is easier to optimize. So I would recommend:
where status = 'PROSES' and
tanggal < date_trunc('year', now()) and
tanggal >= date_trunc('year', now()) - interval '1 year'
This just uses now() rather than current_date because it is easier to type.

Related

Combine multiple selects for statistics generation into on result set

Hey Pros,
I am far away to have good knowledge about SQL, and would ask you to give me some hints.
Currently we aggregate our data with python and I would try to switch this when possible to. (SQL (Postgresql server)
My goal is to have one statment that generate an average for two seperates column's for specific time intervals (1 Hour, 1 Day, 1 Week, Overall) also all events in each period shoud be counted.
I can create 4 single statments for each interval but strugle how to combine this four selects into on result set.
select
count(id) as hour_count,
camera_name,
round(avg("pconf")) as hour_p_conf,
round(avg("dconf")) as hour_d_conf
from camera_events where timestamp between NOW() - interval '1 HOUR' and NOW() group by camera_name;
select
count(id) as day_count,
camera_name,
round(avg("pconf")) as day_p_conf,
round(avg("dconf")) as day_d_conf
from camera_events where timestamp between NOW() - interval '1 DAY' and NOW() group by camera_name;
select
count(id) as week_count,
camera_name,
round(avg("pconf")) as week_p_conf,
round(avg("dconf")) as week_d_conf
from camera_events where timestamp between NOW() - interval '1 WEEK' and NOW() group by camera_name;
select
count(id) as overall_count,
camera_name,
round(avg("pconf")) as overall_p_conf,
round(avg("dconf")) as overall_d_conf
from camera_events group by camera_name;
When possbile the result should look like the data on image
Some hints would be great, thank u
Consider conditional aggregation by moving WHERE logic to CASE statements in SELECT. Alternatively, in PostgreSQL use FILTER clauses.
select
camera_name,
count(id) filter(timestamp between NOW() - interval '1 HOUR' and NOW()) as hour_count,
round(avg("pconf") filter(timestamp between NOW() - interval '1 HOUR' and NOW())) as hour_p_conf,
round(avg("dconf") filter(timestamp between NOW() - interval '1 HOUR' and NOW())) as hour_d_conf,
count(id) filter(timestamp between NOW() - interval '1 DAY' and NOW()) as day_count,
round(avg("pconf") filter(timestamp between NOW() - interval '1 DAY' and NOW())) as day_p_conf,
round(avg("dconf") filter(timestamp between NOW() - interval '1 DAY' and NOW())) as day_d_conf,
count(id) filter(timestamp between NOW() - interval '1 WEEK' and NOW()) as week_count,
round(avg("pconf") filter(timestamp between NOW() - interval '1 WEEK' and NOW())) as week_p_conf,
round(avg("dconf") filter(timestamp between NOW() - interval '1 WEEK' and NOW())) as week_d_conf,
count(id) as overall_count,
round(avg("pconf")) as overall_p_conf,
round(avg("dconf")) as overall_d_conf
from camera_events
group by camera_name;
The simplest way is to join them. For example:
select
coalesce(h.camera_name, d.camera_name, w.camera_name) as camera_name
h.hour_count, h.hour_p_conf, h.hour_d_conf
d.day_count, d.day_p_conf, d.day_d_conf
w.week_count, w.week_p_conf, w.week_d_conf
from (
-- hourly query here
) h
full join (
-- daily query here
) d on d.camera_name = h.camera_name
full join (
-- weekly query here
) w on w.camera_name = coalesce(h.camera_name, d.camera_name)

How to get min value of all cities of yesterday?

How to get min value(temp) of all cities of yesterday.
I want:
Indore:min value:yesterday date
Bhopal:min value:yesterday date
Mumbai:min value:yesterday date
In Postgres, you can do:
select name, min(temp)
from t
where write_date < current_date and
write_date >= current_date - interval '1 day'
group by name;
You can also write the where clause as:
where date_trunc('day', write_date) = current_date - interval '1 day'
However, using the function date_trunc() prevents the use of the index for the where clause.
select name, min(temp) from table
where date(write_date) BETWEEN TRUNC(SYSDATE - 1)
AND TRUNC(SYSDATE) - 1/86400
group by name
this will do your job

PostgreSQL querying the current week's data

I'm trying to grab all the appointments that have been booked for this current week I initially tried this:
select *
from appointments
where staff_id = 'id'
and (to_timestamp(appointments.start_time)) > (current_date - interval '1 week')
and (to_timestamp(appointments.start_time)) < (current_date + interval '1 week')
This just selects all the appointments that equal +/- 7 days, so not the current week. This was my next try. I know its broken but I think it gets the point across.
select *
from appointments
where staff_id = 'id'
and (to_timestamp(appointments.start_time)) > (current_date - interval concat(extract(dow from current_date), ' days'))
and (to_timestamp(appointments.start_time)) < (current_date + interval concat(7 - extract(dow from current_date), ' days'))
How would I go about building this query?
If you agree with Postgres's definition of a week, then you can do:
select a.*
from appointments a
where staff_id = 'id' and
to_timestamp(appointments.start_time) >= date_trunc('week', current_date) and
to_timestamp(appointments.start_time) < date_trunc('week', current_date) + interval '1 week';

Trouble pulling daily data - day resets at 5 PM

I am trying to pull daily data using PostgreSQL. My problem is that the day seems to 'reset' at around 5 PM (Los Angeles Time). Is there a workaround this problem? Here is my query:
SELECT COUNT(distinct be.booking_id)AS "Number of Bookings Today"
FROM booking_events be
WHERE be.event IN ('approve') AND
be.created_at >= current_date AND
be.created_at < current_date + interval '1 day';
You can use hours to offset the current date. I think the logic is:
SELECT COUNT(distinct be.booking_id) as "Number of Bookings Today"
FROM booking_events be
WHERE be.event IN ('approve') AND
be.created_at >= current_date - interval '7 hour' AND
be.created_at < current_date + interval '1 day' - interval '7 hour';

postgres query to check for records not falling between two time periods using the ISO WEEK number and year from DB

i do have a query which works fine but I was just wondering if there are other ways or alternate method to bettter this.
I have a table where i am fetching those records exceeding or do not fall between 1 year time interval however there is only the year and ISO week number column in the table (integer values).
basically the logic is to check ISO WEEK - YEAR falls between 'current_date - interval '1 year' AND current_date.
My query is as below :
select * from raj_weekly_records where
(date_dimension_week > extract(week from current_date) and date_dimension_year = extract(year from current_date) )
or (date_dimension_week < extract(week from current_date) and (extract(year from current_date)-date_dimension_year=1) )
or(extract(year from current_date)-date_dimension_year>1);
Here date_dimension_week and date_dimension_year are the only integer parameters by which I need to check is there any other alternate or better way?.This code is working fine no issues here.
Here is an idea. Convert the year/week to a numeric format: YYYYWW. That is, the year times 100 plus the week number. Then you can do the logic with a single comparison:
select *
from raj_weekly_records
where date_dimension_year * 100 + date_dimension_week
not between (extract(year from current_date) - 1) * 100 + extract(week from current_date) and
extract(year from current_date) * 100 + extract(week from current_date)
(There might be an off-by one error, depending on whether the weeks at the ends are included or excluded.)
select *
from raj_weekly_records
where
date_trunc('week',
'0001-01-01 BC'::date + date_dimension_year * interval '1 year'
)
+ (date_dimension_week + 1) * interval '1 week'
- interval '1 day'
not between
current_date - interval '1 year' and current_date