New to SQL, but trying to learn/do a job for a friend. I have a query set up that returns the number of bookings for the day. Example snippet:
...
WHERE be.event IN ('instant_approve', 'approve') AND TO_CHAR(be.created_at, 'yyyy-mm-dd') BETWEEN '2017-06-26' AND '2017-06-26';
Now, this query is set up for just today. How can I set this up so that tomorrow the query is executed for '2017-06-27' and so on? Is this possible?
Built-in function now() gives you a timestamp of the beginning of your transaction (CURRENT_TIMESTAMP pseudo-constant is its "alias", a part of SQL standard, but I prefer using the function).
Another function, date_trunc() gives you a "truncated" timestamp and you can choose, how to truncate it. E.g., date_trunc('day', now()) will give you the date/time of beginning of the current day.
Also, you can add or subtract intervals easily, so here is an example that gives you the beginning of the current and the next days:
select
date_trunc('day', now()) cur_day_start,
date_trunc('day', now() + interval '1 day') as next_day_start
;
Also, I would not use to_char() or anything else on top of created_at column -- this will not allow Postgres planner use index on top of this field. If you do want to use to_char(), then consider adding a functional index over to_char(created_at, 'yyyy-mm-dd').
Here is how I would retrieve records generated at July 26, 2017:
where
created_at between '2017-06-26' and '2017-06-27'
(implicit type casting from text to timestamps here)
This is equivalent to
where
created_at >= '2017-06-26'
and created_at <= '2017-06-27'
-- so all timestamps generated for July 26, 2017 will match. And for such query Postgres will use a regular index created for created_at column (if any).
"Dynamic" version:
where
created_at between
date_trunc('day', now())
and date_trunc('day', now()) + interval '1 day'
Use current_date built-in function in the between condition and it will work only for today's bookings.
.........
WHERE be.event IN ('instant_approve', 'approve') AND TO_CHAR(be.created_at, 'yyyy-mm-dd') =current_date;
Related
sql table
here in the table above named carpooling contains a column name start_on which has date time as timestamp i have to write a query to select all the rows having date as 25-11-20 using to_char and to_date.
You write a timestamp literal like this:
timestamp '2020-11-25 00:00:00'
so the full filtering condition will be
where start_on >= timestamp '2020-11-25 00:00:00'
and start_on < timestamp '2020-11-26 00:00:00'
Note that dates and timestamps are different in Oracle, and dates include times down to the second (this is for historical reasons - originally there was only the date type, and timestamp was added much later).
Use the TRUNC function, along with date and interval literals:
SELECT *
FROM CARPOOLING
WHERE START_ON BETWEEN DATE '2020-11-25'
AND (DATE '2020-11-26' - INTERVAL '0.000001' SECOND)
You can simply use to_date, but it's recommended to remove the time when comparing the dates. Otherwise, rows having the same date, but a different time will not be selected. Removing the time can be done using TRUNC.
So you can do something like this:
SELECT * FROM carpooling
WHERE TRUNC(start_on) = TO_DATE('2020-11-25','yyyy.mm.dd');
If you don't want to check the 25th of November 2020, but another data, change the date to match your goal.
I have a SQL query which gives different set of result when I use condition
DATE_TRUNC('DAY', timestamp) BETWEEN date_trunc('DAY', NOW()) - interval '14' day AND date_trunc('DAY', NOW())
and a different result when I use condition
timestamp BETWEEN date_trunc('DAY', NOW()) - interval '14' day AND date_trunc('DAY', NOW())
After cross checking both the query results I found that first condition is giving correct result.
Can someone please tell me the difference between both the conditions.
Thanks in advance
timestamp has a time component.
date_trunc(day, timestamp) removes the time component.
The second part of the comparison is different. The first version returns any time on the current day.
The second version only returns midnight on the current day.
Incidentally, I would recommend:
where timestamp >= current_date - interval '14 day' and
timestamp < current_date + interval '1 day'
This works, regardless of whether the timestamp column has a time component or not. And, it is friendly to the optimizer and index usage.
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.
For some reason I'm kind of lost on how to archive:
SELECT * FROM table WHERE timestamp IS WITHIN THIS MONTH;
I've looked at https://www.postgresql.org/docs/9.4/static/functions-datetime.html, but are only able to select X days backwards.
I'm running PostgreSQL 9.4
... WHERE date_trunc('month', timestamp)
= date_trunc('month', current_timestamp);
Alternatively:
... WHERE timestamp >= date_trunc('month', current_timestamp)
AND timestamp < date_trunc('month', current_timestamp) + INTERVAL '1 month';
The second version can use an index on timestamp, the first would need one on the expression date_trunc('month', timestamp).
Why don't you just filter the month with between ?
Pass the start of this month as variable1, and the end of this month as variable2...
SELECT * FROM table WHERE
timestamp >= __month_start AND timestamp < __next_month_start
e.g.
SELECT * FROM table
WHERE
(
timestamp >= '20170701'::timestamp
AND
timestamp < '20170801'::timestamp
)
Unlike using functions in the where-clause, this maintains sargability.
What Laurenz Albe suggested will work, however you're going to have a performance penalty because you'll lose cardinality on that field, you either have to index expression you're going to query (Apparently PostgreSQL allows to do that: https://www.postgresql.org/docs/current/static/indexes-expressional.html) or create a separate column to store yyyy-mm values and query it.
I am creating a Data Model in PowerPivot and am wondering if there is anyway I can create a dynamic date table in SQL. I was able to create one in PowerQuery however there are some bugs in PowerQuery(read only connection) when a table is modified in PowerPivot. What I am looking for is to have a start date of 1/1/2013 (interval is days) and as each new year rolls around rows are added to the date table. Is there anyway to do this?
I am running Postgres
So far I came up with this,
SELECT * FROM dbo.fof_GetDates('1/1/2013', GETDATE())
But I want it to display all dates till end of the year.
The completely dynamic approach would be a query based on generate_series():
SELECT the_date::date
FROM generate_series('2013-01-01 0:0'::timestamp
, date_trunc('year', now()::timestamp)
+ interval '1 year - 1 day'
, interval '1 day') the_date;
Always use ISO 8601 format for dates and timestamps, which works irregardless of locale settings.
A final cast to date (the_date::date), because the function returns timestamp (when fed timestamp arguments).
The expression
date_trunc('year', now()::timestamp) + interval '1 year - 1 day'
calculates the last day of the current year. Alternatively you could use EXTRACT (year FROM now())::text || '-12-31')::date, but that's slower.
You can wrap this into a custom "table-function" (a.k.a. set-returning function) that you can basically use as drop-in replacement for a table name in queries:
CREATE OR REPLACE FUNCTION f_dates_since_2013()
RETURNS SETOF date AS
$func$
SELECT the_date::date
FROM generate_series('2013-01-01 0:0'::timestamp
, date_trunc('year', now()::timestamp)
+ interval '1 year - 1 day'
, interval '1 day') the_date;
$func$ LANGUAGE sql STABLE;
Example:
SELECT * FROM f_dates_since_2013();
Going one step further, you could create a table or - more elegantly - a MATERIALIZED VIEW based on this function (or the underlying query directly):
CREATE MATERIALIZED VIEW my_dates(the_date) AS
SELECT * FROM f_dates_since_2013();
Call:
SELECT * FROM my_dates;
All you have to do now is to schedule a yearly cron job that runs REFRESH MATERIALIZED VIEW at the start of each new year:
REFRESH MATERIALIZED VIEW my_dates;