I want to get the data from the last 28 days and only include complete days. So what I mean is, when I look at the data today at 10:00 AM, it only includes data from yesterday (the completed day) and 28 days before yesterday.
I am creating a live dashboard with figures like this. So I don't want the numbers to change until the day is finished.
Also, I am willing to understand the difference between CURRENT_DATE and CURRENT_TIMESTAMP
For example, in my code, if I use CURRENT_TIMESTAMP, will I get the data from today 10:00 AM back to 28 days ago 10:00 AM? if not, how can I get data in a way numbers change live according to every time I run the code (the average time that data change in the database is 10 minutes).
My simplified code:
select count(id) from customers
where created_at > CURRENT_DATE - interval '28 days'
Maybe I am using wrong code, can you please give me advice on how to get the date in both formats:
include only complete days(does not include today, until the day is
finished)
include hours, from today morning until 28 days back same
time in the morning.
Assuming created_at is of type timestamptz.
include only complete days(does not include today, until the day is
finished)
Start with now() and use date_trunc():
SELECT count(*)
FROM customers
WHERE created_at < date_trunc('day', now())
AND created_at >= date_trunc('day', now() - interval '28 days');
Or work with CURRENT_DATE ...
WHERE created_at < CURRENT_DATE
AND created_at >= CURRENT_DATE - 28;
The result for both depends on the current timezone setting. The "date" functionally depends on your current time zone. The type timestamp with time zone (timestamptz) does not. But the expression date_trunc('day', now()) introduces the same dependency as the "day" is defined by your current time zone. So you need to define which "days" you mean precisely. Basics:
Ignoring time zones altogether in Rails and PostgreSQL
You can subtract integer values from a date to subtract days:
How do I determine the last day of the previous month using PostgreSQL?
now() is a shorter equivalent of CURRENT_TIMESTAMP. See:
Difference between now() and current_timestamp
count(*) is equivalent to count(id) while id is defined NOT NULL, but a bit faster.
I have different results from query for COUNT('e.id') or COUNT(e.id)
include hours, from today morning until 28 days back same time in the morning.
Simply:
WHERE created_at > now() - interval '28 days'
No dependency on the current time zone.
Related
I have a problem very similar to this StackOverflow question in that I need a full seven days of records. My query looks something like this:
SELECT id, entry_timestamp
FROM entries
WHERE created_on >= TO_DATE('2023-01-25', 'YYYY-MM-DD') at time zone 'UTC' - interval '7 days'
ORDER BY entry_timestamp
In my table entry_timestamp is a "timestamp without timezone" column and created_on is a "date" column.
(I need the TO_DATE() instead of current_date because I need to be able to specify a particular date)
When I run that query I get results with entry_timestamp from the last six days.
If I change it to interval '8 days' I get ten days for some reason.
What am I missing that is causing such a broad miscalculation?
I'm trying to get the data between last weeks monday and last week sunday. I'm having trouble with getting the relative part. I'm trying like this:
where date <= LASTWEEKSUNDAY OR date >= LASTWEEKMON
The closest I got to what I seek was using now(), but it returned also some days from the current week. Thanks in advance
You are describing:
where date >= date_sub(date_trunc(current_date, week(Monday), interval 1 week) and
date < date_trunc(current_date, week(Monday))
Although the function calls change, the same logic works on datetimes and timestamps.
Of course week(Monday) is the default for isoweek, so you can use:
where date >= date_sub(date_trunc(current_date, isoweek, interval 1 week) and
date < date_trunc(current_date, isoweek)
I think it's what you want
where date between DATE_SUB(DATE_TRUNC(CURRENT_DATE(), WEEK(SUNDAY)), interval 6 day) and DATE_TRUNC(CURRENT_DATE(), WEEK(SUNDAY))
You shouldn't use OR in the where statement, it'll cover all the days if you use OR. Instead, you can prefer using AND or between.
I am trying to include, in my where clause, a way to automatically pull data for the previous day based on my current timezone. All of my data is stored with a UTC timestamp.
I can change my timestamp from UTC to my timezone ("America/Chicago") and I can automatically pull data for the last X days; for example, for the prior week, without having to manually enter a date. But I cannot figure out how to do both simultaneously in my where clause.
SELECT *
FROM `my-data-set`
WHERE
event_time >= CAST(DATE_SUB(CURRENT_DATE(), INTERVAL 7 DAY) AS TIMESTAMP)
AND event_time < CAST(DATE_SUB(CURRENT_DATE(), INTERVAL 0 DAY) AS TIMESTAMP)
I would like to be able to look at the previous week or day in my timezone, not the previous UTC day.
You can do specify the timezone:
where date(event_time, 'America/Chicago') = date_add(current_date, interval -1 day)
Note that the parentheses are not needed for current_date.
The key to the logic is converting the UTC timestamp to a date in your local time.
I have a table(pkg_date) in redshift. I want to fetch some data for every date for the last 3 months.
Here is my query
select * from pkg_data where scan_date < current_date;
How can I use current_date as a variable in the query itself and run this query for every date from April 1.
I have set a cron job which will run in every hour. In every hour it should run with different current_date
SELECT *
FROM pkg_data
WHERE scan_date > CURRENT_DATE - INTERVAL '3 months'
Be careful — Redshift works in UTC, so the CURRENT_DATE might suffer from timezone effects and be +/- what you expect sometimes.
SELECT
CURRENT_DATE,
(CURRENT_DATE - INTERVAL '3 months')::date
Returns:
2018-06-21 2018-03-21
Also be careful with strange lengths of months!
SELECT DATE '2018-05-31' - INTERVAL '3 months'
returns:
2018-02-28 00:00:00
Notice that it gave the last day of the month (31st vs 28th).
By the way, you can use DATE '2018-05-31' or '2018-05-31'::DATE, and also INTERVAL '3 months' or '3 months'::INTERVAL to convert types.
Use dateadd() for getting date 3 moth old day and GETDATE() for get current date.
ie code will look like.
select * from pkg_data where scan_date < dateadd(month,-3,GETDATE());
for cron refer How to execute scheduled SQL script on Amazon Redshift?
The following query against Postgres database some how leaves few rows for the date: 2017-10-01. I have added time zone also. Is there a way to solve this issues?
select min(p.start_timestamp AT TIME ZONE p.timezone AT TIME ZONE 'America/Phoenix') as Date,
'America/Phoenix' AS Timezone, sum(GREATEST(0, p.value)) as Value, p.uom as UnitOfMeasurement
from main.production_ts_2017_10 p
where p.start_timestamp AT TIME ZONE p.timezone >= to_date('2017-09-30','YYYY-MM-DD') + INTERVAL '2 day'
and p.start_timestamp AT TIME ZONE p.timezone <= '2017-10-30'
and p.serial_number = '5T7842974Z'
group by date_trunc('hour', p.start_timestamp AT TIME ZONE p.timezone AT TIME ZONE 'America/Phoenix'), p.uom
order by Date
Let's simplify it down to just this part of the query:
p.start_timestamp AT TIME ZONE p.timezone >= to_date('2017-09-30','YYYY-MM-DD') + INTERVAL '2 day'
This is a conditional expression around the >= operator. It has a left-hand side (p.start_timestamp AT TIME ZONE p.timezone) and a right-hand side: (to_date('2017-09-30','YYYY-MM-DD') + INTERVAL '2 day') that are each evaluated separately, so the final conditional result (true/false) can be determined for each record.
Postgres database some how leaves few rows for the date: 2017-10-01
Look again at the right-hand side of the expression:
to_date('2017-09-30','YYYY-MM-DD') + INTERVAL '2 day'
That reduces down to this value:
'2017-10-02'
In other words, you're limited to records that come after '2017-10-01'. Do you really want that INTERVAL section in there? Did you want to subtract two days instead of add?
Let's assume two things:
You're asking "why does this query show a few rows for October 1st when it should show only rows for October 2nd or later"
p.start_timestamp is of type TIMESTAMP WITHOUT TIME ZONE (I feel safe in assuming this, because otherwise the double-timezone casting of it in other parts of the query makes no sense).
You have this WHERE clause:
where p.start_timestamp AT TIME ZONE p.timezone >= to_date('2017-09-30','YYYY-MM-DD') + INTERVAL '2 day'
Now, the left-hand side of the query is p.start_timestamp AT TIME ZONE p.timezone which will evaluate to a TIMESTAMP WITH TIME ZONE. The right-hand side of the query, however, is to_date('2017-09-30','YYYY-MM-DD') + INTERVAL '2 day' which evaluates to a TIMESTAMP WITHOUT TIMEZONE.
Whenever you compare a TIMESTAMP WITH TIMEZONE to a TIMESTAMP WITHOUT TIMEZONE, the results are going to be dependent on your current TimeZone setting in your psql session, because the TIMESTAMP-no-TZ will be evaluated as if it is in the psql TimeZone. For example, 12:31AM in 'America/Phoenix' on October 2nd can be 11:31AM in 'America/Los_Angeles', depending on the date (and BTW, you chose the worst possible time zone as your default, because America/Phoenix is just wierd). This would result in you seeing records from October 1st, depending on the value of p.timezone.
You're compounding the problem with this:
select min(p.start_timestamp AT TIME ZONE p.timezone AT TIME ZONE 'America/Phoenix') as Date
... so now you're displaying all timestamps as America/Phoenix timestamps regardless of what timezone they were originally in, or what timezone they were compared with. If your TimeZone setting is UTC, you'll see a LOT of October 1st records, because Oct 2nd in UTC overlaps with Oct 1st in America/Phoenix for six or seven hours depending on the date.
I suspect, given the rest of the query, what you want for that WHERE clause is:
where ( p.start_timestamp AT TIME ZONE p.timezone )
>=
( to_date('2017-09-30','YYYY-MM-DD') + INTERVAL '2 day' )
AT TIME ZONE 'America/Phoenix'
AND p.start_timestamp AT TIME ZONE p.timezone
<=
( TIMESTAMP '2017-10-30' AT TIME ZONE 'America/Phoenix' )
All of this is an illustrative lesson in why you should be storing all of your timestamp data as TIMESTAMP WITH TIME ZONE, instead of what you're doing here. As long as you're storing the timezone in a separate field an using AT TIME ZONE all the time, you're going to keep breaking queries. Also, with all of this casting time zones, any indexes you have on those time columns are unlikely to be used.