I want to use the DEFINE
command in Oracle to define strings and evaluate them in the SELECT
, FROM
and WHERE
clauses of a query.
I want to select all the credits that started in January 2018 from the tables credits_201801
, credits_201802
, credits_201803
, credits_201804
, credits_201805
and credits_201806
. In other words, I want to visualize the behavior of the January 2018 credits 0, 1, 2, 3, 4 and 5 months after they started.
For example, I tried the following code to check the status of the Jan 2018
credits in Feb 2018
:
DEFINE crop = '2018-01-01'; DEFINE crop_n = ADD_MONTHS(&crop, 1); -- I want this to return 2018-01-01 plus `n = 1` months DEFINE table_ = REPLACE(SUSBTR(&crop_n, 1, 7), '-'); -- I want this to return '201802' SELECT PERSON_ID, BANK_ID, ACCOUNT_ID, START_DATE, MONTHS_BETWEEN(&crop_n, &crop) AS PERIOD, DAYS_OVERDUE FROM 'MDB.CREDITS_' || &table_ -- I want this to be evaluated as 'MDB.CREDITS_201802' WHERE START_DATE >= &crop -- Credits that started on or after Jan 1 2018 AND START_DATE < ADD_MONTHS(&crop, 1) -- Credits that started before Feb 1 2018
The user-defined variables are working well in the SELECT
clause, but it seems that the FROM
section is evaluating the table as a literal string rather than the name of the table. The WHERE
clause is not working either.
I specifically need used DEFINE
because it’s the only command I know of that doesn’t require me to use INSERT INTO
(I am only allowed to select).
Advertisement
Answer
A date is written like date '2018-01-01'
, not '2018-01-01'
.
define
expects a single value, so if you want it to include blank spaces then you’ll need to quote it.
To construct a string in YYYYMM
format from a date, you need to use to_char(dateval,'YYYYMM')
.
You also need to evaluate the table_
expression so you can substitute a literal string into the table name in the final query.
define crop = "date '2018-01-01'" define crop_n = "add_months(&crop, 1)" -- I want this to return 2018-01-01 plus `n = 1` months column table_ new_value table_ select to_char(&crop_n,'YYYYMM') as table_ from dual; prompt crop = &crop prompt crop_n = &crop_n prompt table_ = &table_ select person_id , bank_id , account_id , start_date , months_between(&crop_n, &crop) as period , days_overdue from MDB.CREDITS_&table_ -- I want this to be evaluated as 'MDB.CREDITS_201802' where start_date >= &crop -- Credits that started on or after Jan 1 2018 and dcredfaperturacta < add_months(&crop, 1) -- Credits that started before Feb 1 2018 /
The column x new_value y
setting captures the last value of column x
into substitution variable y
. It’s originally meant for page headers in reports, but very handy for scripting. You can hide the output using set termout off
. (set termout on
to restore terminal output.)
This will generate and run
crop = date '2018-01-01' crop_n = add_months(date '2018-01-01', 1) table_ = 201802 select person_id , bank_id , account_id , start_date , months_between(add_months(date '2018-01-01', 1), date '2018-01-01') as period , days_overdue from MDB.CREDITS_201802 -- I want this to be evaluated as 'MDB.CREDITS_201802' where start_date >= date '2018-01-01' -- Credits that started on or after Jan 1 2018 and dcredfaperturacta < add_months(date '2018-01-01', 1) -- Credits that started before Feb 1 2018
Note following comments: this is Oracle SQL*Plus syntax. Other tools such as Toad, PL/SQL Developer and SQL Developer support it to some extent and using different methods. Not all SQL*Plus syntax is guaranteed to work in all other tools. In PL/SQL Developer it only works in a Command Window. In SQL Developer you will need to use “Run as Script” (F5) and not the regular “Run” (Ctrl-Enter).