How to use a local variable in oracle SQL? - sql

I have some MariaDB SQLs that are called by a bash script, this script set the start and end dates for the queries, but now the project will use Oracle DB.
So, I have something like this in MariaDB SQL:
SET #date_start := '2000-01-01';
SET #date_end := '2001-01-01';
SELECT * FROM user WHERE birth BETWEEN #date_start AND #date_end;
And I couldn't find anything like that in Oracle SQL, already tried DECLARE, DEFINE, WITH, but nothing works

In order to use parameters in Oracle, you have to use PL/SQL. However, if you just want to parameterize a single query, you can use a CTE:
WITH params AS (
SELECT DATE '2000-01-01' as date_start,
DATE '2001-01-01' as date_end
FROM dual
)
SELECT u.*
FROM params CROSS JOIN
user u
WHERE u.birth BETWEEN params.date_start AND params.date_end;
Similar logic works in just about any database (although dual may not be needed and the date constants might have different formats).

Related

How to reuse a computed value multiple times?

Basically I just want a simple way of finding the most recent date in a table, saving it as a variable, and reusing that variable in the same query.
Right now this is how I'm doing it:
with recent_date as (
select max(date)
from mytable
)
select *
from mytable
where date = (select * from recent_date)
(For this simple example, a variable is overkill, but in my real-world use-case I reuse the recent date multiple times in the same query.)
But that feels cumbersome. It would be a lot cleaner to save the recent date to a variable rather than a table and having to select from it.
In pseudo-code, something like this would be nice:
$recent_date = (select max(date) from mytable)
select *
from mytable
where date = $recent_date
Is there something like that in Postgres?
Better for the simple case
For the scope of a single query, CTEs are a good tool. In my hands the query would look like this:
WITH recent(date) AS (SELECT max(date) FROM mytable)
SELECT m.*
FROM recent r
JOIN mytable m USING (date)
Except that the actual example query would burn down to this in my hands:
SELECT *
FROM mytable
ORDER BY date DESC NULLS LAST
FETCH FIRST 1 ROWS WITH TIES;
NULLS LAST only if there can be NULL values. See:
Sort by column ASC, but NULL values first?
WITH TIES only if date isn't UNIQUE NOT NULL. See:
Get top row(s) with highest value, with ties
In combination with an index on mytable (date) (or more specific), this produces the best possible query plan. Look no further.
No, I need variables!
If you positively need variables scoped for the same command, transaction, session or more, there are various options.
The closest thing to "variables" in SQL in Postgres are "customized options". See:
User defined variables in PostgreSQL
You can only store text, any other type has to be cast (and cast back on retrieval).
To set and retrieve a value from within a query, use the Configuration Settings Functions set_config() and current_setting():
SELECT set_config('foo.recent', max(date)::text, false) FROM mytable;
SELECT *
FROM mytable
WHERE date = current_setting('foo.recent')::date;
Typically, there are more efficient ways.
If you need that "recent date" a lot, consider a simple function as "global variable", usable by all transactions in all sessions (but each new command sees its own current state):
CREATE FUNCTION f_recent_date()
RETURNS date
LANGUAGE sql STABLE PARALLEL SAFE AS
'SELECT max(date) FROM mytable';
STABLE is a valid volatility setting as the function returns the same result within the same query. Be sure to actually make it STABLE, so Postgres does not evaluate repeatedly. In Postgres 9.6 or later, also make it PARALLEL SAFE. Then your query becomes:
SELECT * FROM mytable WHERE date = f_recent_date();
More options:
Is there a way to define a named constant in a PostgreSQL query?
Passing user id to PostgreSQL triggers
Typically, if I need variables in Postgres, I use a PL/pgSQL code block in a function, a procedure, or a DO statement for ad-hoc use without the need to return rows:
DO
$do$
DECLARE
_recent_date date := (SELECT max(date) FROM mytable);
BEGIN
PERFORM * FROM mytable WHERE date = _recent_date;
-- more queries using _recent_date ...
END
$do$;
PL/pgSQL may be what you should be using to begin with. Further reading:
When to use stored procedure / user-defined function?
Keep in mind that in SQL you cannot directly declare a variable. Basically a CTE is creating variable (or a set of) and in SQL to use a variable you select it. However, if you want to avoid that structure you can just get the variable directl from a subset directly.
select *
from mytable
where date = (select max(date) from mytable);

How to create a function that can operate with the current date and a value from my table in sql

I have a Clients table with the inscriptiondate which is a date. I want to create a function that I give the value inscriptiondate(from my table) and do the value-currdate(). Is it possible?
I'm using SQL server, But I would also like to know how to do in Mysql if its different.
In MySQL you would typically do:
select datediff(curdate(), inscriptiondate) as days_between
In MS SQL, you would typically do:
select datediff(day, inscriptiondate, getdate())

ORACLE SQL create date from table colum parts

I'm trying to create a select statement that returns one row (date) combining 3 column entries
My idea that doesn't work:
SELECT
TO_DATE( d_date.day_varchar +
d_date.month_varchar +
d_date.year_varchar , 'DD/MM/YYYY')
FROM d_date
Is this possible in Oracle SQL and how can I get this result?
In SQL Server there is a DATEFROMPARTS() function but I don't know that well Oracle specifics ...
Your approach seems fine. You just need to update it for Oracle syntax:
select to_date(d_date.year_varchar || d_date.month_varchar || d_date.day_varchar, 'YYYYMMDD')
It is a curious that you would have a table with date parts, but not the actual dates.

Date functions in temporal tables

Since SQL Server 2016 it is possible to automatically create Temporal Tables. I wanted to create a simple query that retrieves the data from a specified date. However, when I try to specify a date in the query like so, it gives a syntax error:
SELECT * FROM Person FOR SYSTEM_TIME AS OF GETDATE()
I even tried to convert the datatype to a datetime2, since the dates a stored like that, but it still wouldn't work:
SELECT * FROM Person FOR SYSTEM_TIME AS OF CONVERT(datetime2,GETDATE())
This problem occurrs, but when I first execute SELECT GETDATE() and then copy the text and paste it into the query, it works fine.
How can I specify a datetime with the AS OF keyword?
Thanks in advance.
Try this:
DECLARE #Date DATETIME2 = GETUTCDATE()
SELECT *
FROM Person
FOR SYSTEM_TIME AS OF #Date
Also, take a look at this article for more examples of querying temporal tables.

Compare date with current_date in Oracle

I can not get what is wrong in this query ( ORACLE QUERY )
SELECT *
FROM HR.CUSTOMER C
dual
WHERE CREATED_AT = current_date
;
I am getting this error
ORA-00933: SQL command not properly ended
There is a dual too many in your query.
Moreover, in Oracle current_date is not the current date for the database, but the current datetime of your session. While your database server may be in a timezone where it is currently 11 p.m., it may be next day 3 a.m. already on your PC. Whenever you spot current_date in an Oracle query it is very likely wrong.
In Oracle use sysdate for now and trunc(sysdate) for today.
select *
from hr.customer
where created_at = trunc(sysdate);
Since you already know the table and wanted to get all the columns from it, you need not use dual
The DUAL table is a special one-row, one-column table present by
default in Oracle and other database installations. In Oracle, the
table has a single VARCHAR2(1) column called DUMMY that has a value of
'X'. It is suitable for use in selecting a pseudo column such as
SYSDATE or USER.
You may just use the following query instead
SELECT *
FROM HR.CUSTOMER
WHERE CREATED_AT = current_date;