How to save temporary session variables in PostgreSQL - sql

Say I have a simple SQL statement like this:
SELECT * from birthday WHERE date < now() + INTERVAL '1 day' AND date > now() - INTERVAL '1 day';
but the equations for the "From" and "To" variables would be something more sophisticated than that. And I will be reusing the results of these equations in multiple queries. So, can I store them temporarily as we do in any programming language? I imagine something like:
$from := now() - INTERVAL '1 day';
$to:= now() + INTERVAL '1 day';
SELECT * from birthday WHERE date < $from AND date > $to;
I tried using SELECT INTO as suggested in this question but that's not what I want because it creates a whole database table just to save the variable, which also causes an error when reusing it in a later session even when using the TEMP parameter. It says "relationship already exists"!
I also tried some dollar sign $ syntax and some colon+equal := syntax and none works

SQL is not any programming language. If you want to store the values so you can re-use them in one query, then you can use a CTE:
WITH params as (
SELECT now() - INTERVAL '1 day' as _from,
now() + INTERVAL '1 day' as _to
)
SELECT *
FROM params CROSS JOIN
birthday b
WHERE date < params._to AND date > params._from;
If you want to repeat this across multiple queries, then I would recommend a temporary table:
CREATE TEMPORARY TABLE params AS
SELECT now() - INTERVAL '1 day' as _from,
now() + INTERVAL '1 day' as _to;
SELECT *
FROM params CROSS JOIN
birthday b
WHERE date < params._to AND date > params._from;
You can also encapsulate the code in a procedure/function. Or use some sort of scripting language or language such as Python.

Related

ERROR: invalid input syntax for type interval

I have a query like the following
CAST(kokyaku1Information2.mail_jyushin as integer) as information2_mail_jyushin,
(date '$mytime' - INTERVAL 'information2_mail_jyushin' day) AS modified_date,
When run the query i get an error like 'invalid input syntax for type interval'. I used another select field named information2_mail_jyushin before day.
In Postgres, you would use interval arithmetics like this:
kyaku1Information2.mail_jyushin::int AS information2_mail_jyushin,
date '$mytime'
- kokyaku1Information2.mail_jyushin::int * interval '1 day'
AS modified_date
Note that concatenating variables in a SQL statement is bad practice, and opens up your code to SQL injection attacks. Instead, use parameters, as in:
$1::date
- kokyaku1Information2.mail_jyushin::int * interval '1 day'
AS modified_date

trunc(add_months(sysdate,3),'Q')-1 equivalent expression in Postgres

can anybody convert this oracle expression trunc(add_months(sysdate,3),'Q')-1) to postgresql?
Basically this expression gives you the last day of the current quarter (provided that you remove the last closing parenthese, which otherwise is a syntax error).
In postgres, you could phrase this as:
date_trunc('quarter', current_date) + interval '3 months' - interval '1 day'
This generates a timestamp value, that you can cast if you want a date (this distinction does not exist in Oracle, where a date stores the time component as well).
The Postgres equivalent of your Oracle calculation can be seen below.
select date_trunc('quarter', current_date + interval '3 month') - interval '1 day'

Selecting rows created up to 30 seconds ago in Postgres

Say I want to find orders made recently. I am trying this statement:
SELECT * FROM orders WHERE time < now() - interval '30 second';
This doe not work (It does not select any row.) although the following works:
SELECT * FROM orders WHERE time < now();
Do I need to use a fixed time variable? Like:
SELECT * FROM orders WHERE time < '2018-07-01 12:00:00' - interval '30 second';
I am guessing that I should not use now() in statements because it can be changing during operations ...
I believe you have the comparison in the wrong direction:
SELECT *
FROM orders
WHERE time > now() - interval '30 second';
This returns values in the last 30 seconds.
This assumes that time is of an appropriate date type for the comparison.

Dynamic Date Table

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;

Add number of days in given date

In PostgreSQL:
Let say:
SELECT DATE(NOW())+interval '1 day';
It will show date tomorrow.
Problem:
While I having a column duration in table tbl, following SQL does not work :
SELECT DATE(NOW())+interval duration || ' day' from tbl;
I just wondering how to make the '1 day' become a variable instead of a constant.
Do not try to make '1day' a variable, just multiply it by duration variable:
SELECT DATE(NOW()+duration * INTERVAL '1day') FROM tbl;