Using a variable in an SQL query (Oracle DBMS)? - sql

I am typing SQL queries to get some data from a software tool which is based on an Oracle database. I am using the typical SELECT-statement.
Now, in my SQL-query I am using at different places the date "02.05.2012". Is there a way to define a variable date_string at the beginning and then use at all relevant places this variable?
This would simplify things a lot. Thanks for all hints and tips!

You might try to rewrite your query to return the literal from an inline view ...
select
my_date,
...
from(
select to_date('02.05.2012','DD.MM.YYYY') my_date from dual),
table2
where
some_column <= my_date

What you look for is a bind variable.
select to-date(:date, 'dd.mm.yyyy') date1
, to-date(:date, 'dd.mm.yyyy') + 1 date2
from dual
On runtime you need to pass the value to the bind variable. It all depends on your programming language how to bind the variable, but there is plenty documentation for that.
DEFINE only works if you use sql*plus, and that's usually not the case inside a "software tool" :)
EDIT:
I'm beginning to understand now. It's just a textarea where you can enter a query and it will execute it and return the result. In that case you either write some complicated pl/sql code, or enter all the dates manually, or use a cross join with a select from dual:
with (select to_date('02.05.2012', 'dd.mm.yyyy') my_date from dual) d
select *
from some_table t
cross join d -- no ON required

If you want to select using the current date you can use sysdate.
Using SQLPLUS you can define your own variables:
SQL> define mydate ="01-05-2012"
SQL> select to_date('&mydate','DD-MM-YYYY') from dual;
01-MAY-12

try the following :
SELECT *
FROM table1
WHERE to_char(date1,'DD/MM/YYYY') = '&&date'
AND to_char(date2,'DD/MM/YYYY') = '&&date'
AND to_char(date3,'DD/MM/YYYY') = '&&date'
you will get a prompt to enter the value for the &&date , if you want to enter different values for each date, you should type &date instead of &&date

DEFINE is useful for your requirement.
DEFINE NAME="example"
access with &NAME

Related

Declare a value in Sparksql in Databricks

I wanted to declare a fixed value before implementing various chunks of queries, and tried the following method. Unfortunately, no values are returned. Any advice will be much appreciated.
SET end_date = '2022-03-01';
—chunk 1
select * from p
where p.SEND_DATE between '2022-02-01' AND ${end_date}
—chunk 2
select * from p
where p.SEND_DATE between '2022-01-01' AND ${end_date}
You would use a widget:
CREATE WIDGET TEXT end_date DEFAULT '2022-03-01';
Then, you can use it in your query with the syntax you have in your question. If you want it to be a DateType instead of a string, then you can turn it into a date with to_date in your query.

Dynamic query using bigquery and data studio

I want to take out data for every date range in Data Studio without the need to change date range selectors in my BigQuery all the time. However, not sure if it is even possible to do so. The reasons I do this is to make sure that the queried data is only for 30 days, as later it do some kind of segmentation using that 30 days data.
Then I figured out that the Data Studio can use dynamic_date, however this way will never produce any datatable (datatable will be used to do other queries from it). Is it possible to do dynamic_date in BigQuery instead? like retrieving data from BigQuery using a date range not previously defined in the query.
From my point of view, code should be like :
SELECT
ID,
FROM `table`
WHERE DATE(Timestamp) between $DS_START_DATE and $DS_START_DATE + INTERVAL 30 DAY)
or
WHERE DATE(Timestamp) >= #DS_START_DATE
I believe in pure Bigquery you can use DECLARE clause for that purpose, defining variables of the specified type:
declare DS_START_DATE date default "2020-03-03";
declare DS_END_DATE date default "2020-03-04";
WITH sample AS (
SELECT '10001' AS id, cast('2020-03-01' AS timestamp) as date_id UNION ALL
SELECT '10002', cast('2020-03-02' AS timestamp) UNION ALL
SELECT '10003', cast('2020-03-03' AS timestamp) UNION ALL
SELECT '10004', cast('2020-03-04' AS timestamp) UNION ALL
SELECT '10005', cast('2020-03-05' AS timestamp) UNION ALL
SELECT '10006', cast('2020-03-06' AS timestamp)
)
select id, date_id from sample
where date(date_id) between DS_START_DATE and DS_END_DATE
Alternatively, you can take a look at parameterized queries, however as I mentioned in the comment, they are not supported in classic BigQuery web UI.

Is there a way to define a named constant/parameter in a single-statement SQL query?

Tried to do something like:
WITH
dates as (SELECT '2015-01-01' as start, '2016-01-01' as end)
SELECT * FROM my_table WHERE start_date >= dates.start AND end_date <= dates.end
But got the error message "Relation 'dates' does not exist" (in Vertica). Is there any proper way to define a constant/parameter. In real example the query contains multiple selects over a defined time range, hence I'd like to maintain the values constants/parameters in a single place to allow them to be reused in the nested subqueries.
IF possible, I'd like to refrain from DECLARE/SET-like statements, where a separate line is required.
I would still do what #GordonLinoff mentioned (I doubt it has much impact on the query plan), but in case you really don't want to or like the feature I will show at the end...
You mentioned you were going to use vsql. You can do variables there.
\set start '2015-01-01'
\set end '2016-01-01'
SELECT *
FROM my_table
WHERE start_date >= :start
AND end_date <= :end;
Which is I guess kind of nice because you can also do things like:
\set start ''`date "+%Y-%m-%d %H:%M:%S"`''
Or echo the result of any command into a variable that you can use as a variable in your sql statement. Note that this variable is quite literal and you need to include any punctuation, quoting, etc. It isn't just a value, it's more like a template.
You need to have dates in the FROM clause if you want it in the query. You can do this as:
WITH dates as (SELECT '2015-01-01' as start, '2016-01-01' as end)
SELECT t.*
FROM my_table t JOIN
dates d
ON t.start_date >= d.start AND t.end_date <= d.end;
Note: You can also do this with a CROSS JOIN. I often write queries as:
WITH params as (
SELECT '2015-01-01' as start, '2016-01-01' as end
)
SELECT t.*
FROM params CROSS JOIN
my_table t
WHERE t.start_date >= params.start AND t.end_date <= params.end;

Bad date format Oracle SQL

I'm facing an issue with date format. I need the row with the max(date1)
I don't think that my query is incorrect :
SELECT column1,
column2,
date1
FROM table
WHERE date1 = (SELECT MAX(date1) FROM table);
When i use this query in dev environment with TOAD, i'm receiving that result :
column1;column2;date1
aaaaa;bbbbb;19/09/2014 14:13:21
But, when i ask our infrastructure to make this query in production, they returned me that result :
column1;column2;date1
ccccc;dddddd;14/09/26
The date isn't in good format... What can i do the receive the good date ? Does i have to specified the format in my query ? Or does the infra team messed up somethings while giving me the result ?
Thanks in advance for your help
date1 is a date column - it doesn't have any intrinsic format - that's up to the client and the environment to determine when printing it.
If you want to control the format, you need to do so explicitly with the to_char function:
SELECT column1,
column2,
TO_CHAR(date1, 'DD/MM/YYYY hh24:mi:ss')
FROM table
WHERE date1 = (SELECT MAX(date1) FROM table);

Select throws an ORA-01858 exception

With the following query, the Oracle exception is thrown.
However, I cant see why. Can anyone shed some light?
select visit_id, to_date(response, 'DD/MM/YYYY') as convertedDate from
(
select *
from dat_results_ext
where item_name = 'CALLBACKDATE'
)
where to_date(response, 'DD/MM/YYYY') > sysdate
I understand the exception to be mean that its trying to convert the 'response' field, but it is meeting a non-numeric. Problem is the row that it should bring back has everything in the right format.
The 'response' field is a varchar field, but all the rows coming back with the 'item_name = 'CALLBACKDATE' clause are all of the correct format.
Any ideas?
The optimizer can rewrite your query before trying to find the best execution plan. In your case since you have no hints that would prevent the optimizer from doing this, it will probably unnest your subquery and rewrite your query as:
SELECT *
FROM dat_results_ext
WHERE item_name = 'CALLBACKDATE'
AND to_date(response, 'DD/MM/YYYY') > sysdate
You don't have control over the order of evaluation of the statements in the WHERE clause, so Oracle probably evaluated the to_date function first on a row that is not convertible to a date, hence the error.
I see two options to force Oracle to evaluate the statements in the order you want:
Use rownum. Rownum will materialize the subquery, preventing Oracle from merging it with the outer query:
SELECT visit_id, to_date(response, 'DD/MM/YYYY') AS convertedDate
FROM (SELECT r.*,
rownum /* will materialize the subquery */
FROM dat_results_ext r
WHERE item_name = 'CALLBACKDATE')
WHERE to_date(response, 'DD/MM/YYYY') > sysdate
Use the NO_MERGE hint:
SELECT visit_id, to_date(response, 'DD/MM/YYYY') AS convertedDate
FROM (SELECT /*+ NO_MERGE */ *
FROM dat_results_ext
WHERE item_name = 'CALLBACKDATE')
WHERE to_date(response, 'DD/MM/YYYY') > sysdate
The TO_DATE clause has to be evaluated before the truth of the WHERE clause can be determined. If you have values of response that can't be evaluated in the TO_DATE function, you'll see the error.
To be very precise, this is caused because some value of response do not match the format mask of DD/MM/YYYY. For example, if your session is set to default date format of DD-MON-YY, execute the following and you will receive the error message:-
select to_date('17/SEP/2012','DD/MM/YYYY') from dual;
ERROR:
ORA-01858: a non-numeric character was found where a numeric was expected
Since you passed a character in the month field and Oracle expects a number.