Save value into a variable in oracle db - sql

I have a query where i have to use the result of it multiple times. So instead of running the query multiple times i want to save the query value into a variable once and use it multiple times to accelerate the query speed.
for example:
Declare VAr = select M_DATE from TBT

If you want to do this in an interactive client, the answer depends on the client. For SQLPlus you could do this:
VARIABLE my_date VARCHAR2(10);
BEGIN
SELECT to_char(sysdate, 'YYYY-MM-DD' ) INTO :my_date FROM dual;
END;
/
PRINT my_date;
SELECT * FROM my_table WHERE date_column = TO_DATE( :my_date, 'YYYY-MM-DD' );
Note that SQLPlus does not support a DATE type for its variables, so you need to convert to a string when storing then back to a date when using the value. I recommend always using an explicit conversion and format string, simply to avoid unexpected results if the default format is not what you are expecting.
Within a PL/SQL block or procedure, it would be a little simpler:
DECLARE
l_mydate DATE;
BEGIN
SELECT sysdate INTO l_mydate FROM dual;
SELECT whatever INTO l_whatever FROM my_table
WHERE date_column = l_mydate;
<etc...>
END;
/

If you want to store the result of the query then you need to use a select ... into;
var v_storedate VARCHAR2(19);
exec select m_date into :v_storedate from tbt;
print v_storedate;
For an anonymous SQL block
begin
select m_date
into :v_storedate
from tbt;
end;
/

Related

How to use SELECT request in stored procedure (Oracle)?

I use Oracle 12c. I know that my next question is not new but I am little bit confused and need help.
I have this SQL statement:
SELECT *
FROM TABLE_NAME
WHERE CREATE_DATE BETWEEN TO_DATE(FIRST_DATE, 'YYYY-MM-DD')
AND TO_DATE(SECOND_DATE , 'YYYY-MM-DD')
Questions:
How correctly to use SELECT request in stored procedure?
That SQL statement returns more than 1 row, is it mean that I need to use cursor?
If table has 15 columns, as output I need to set all of them?
EDIT:
CREATE OR REPLACE PROCEDURE PROCEDURE_NAME
(
FIRST_DATE IN VARCHAR2(10),
SECOND_DATE IN VARCHAR2(10)
)
AS
oracle_cursor SYS_REFCURSOR;
BEGIN
OPEN oracle_cursor FOR
SELECT *
FROM scheme_name.table_name
WHERE CREATE_DATE BETWEEN TO_DATE(FIRST_DATE, 'YYYY-MM-DD') AND TO_DATE(SECOND_DATE, 'YYYY-MM-DD');
DBMS_SQL.RETURN_RESULT(oracle_cursor);
END PROCEDURE_NAME;
How correctly to use SELECT request in stored procedure?
In a stored procedure you need to assign the queried result set to a variable (or variables) which match the projection:
select << column >>, << column >>
into << variable >>, << variable >>
from table_name
....
That SQL statement returns more than 1 row, is it mean that I need to use cursor?
A cursor is one way of handling it. Although a cursor loop is usually the better approach:
for r in ( SELECT *
FROM TABLE_NAME
WHERE CREATE_DATE BETWEEN TO_DATE(FIRST_DATE, 'YYYY-MM-DD')
AND TO_DATE(SECOND_DATE , 'YYYY-MM-DD')
) loop
Populating a collection variable is another approach, using the BULK COLLECT:
select << column >>
bulk collect into << collection >>
from table_name
....
If table has 15 columns, as output I need to set all of them?
You can choose to create fifteen distinct variables. However, if your query's projection matches the table's projection (which it does with select *) you can use the %rowtype construct to define a record variable or a collection:
declare
l_rec TABLE_NAME%rowtype; -- single row
type t_rec is table of TABLE_NAME%rowtype; -- multiple rows
l_recs t_rec
begin
SELECT *
bulk collect into l_recs
FROM TABLE_NAME
WHERE CREATE_DATE BETWEEN TO_DATE(FIRST_DATE, 'YYYY-MM-DD')
AND TO_DATE(SECOND_DATE , 'YYYY-MM-DD');
I need to take the result and show that data in web page.
For returning results you probably just need to return a Ref Cursor. This is just a pointer which maps to constructs like JDBC ResultSet and ODBC ResultSet. For PHP this would be an oci_new_cursor. Find out more.
Create or replace procedure get_recs
(FIRST_DATE in varchar2,
SECOND_DATE in varchar2,
OUT_RECS out sys_refcursor
) is
Begin
Open out_recs for
SELECT *
FROM TABLE_NAME
WHERE CREATE_DATE BETWEEN TO_DATE(FIRST_DATE, 'YYYY-MM-DD')
AND TO_DATE(SECOND_DATE , 'YYYY-MM-DD');
End;
Incidentally, you seem to expect to pass the parameters as strings: it would be better to pass them as actual dates.

Use format pattern from regexp_replace in to_char

I have a SQL stored in a column where the format for date is in square brackets:
sql_column
------------------------------------------------------------------------------
select col1 from table1 where col2 = to_date('[DD-MON-YYYY]', 'DD-MON-YYYY');
select col1 from table2 where col2 between [YYYYMMDD]00000 and [YYYYMMDD]99999 and col3 = to_date('[DD-MON-YYYY]', 'DD-MON-YYYY');
....
I don't know which format can be there beforehand, but it is always a date format.
Is there a way to use regexp_replace (or regexp_substr or even with regexp_* functions) to find and replace the pattern with the result of to_char of my given date and pattern taken from the db column.
Perhaps something like this (which doesn't work obviously):
select sql_column,
regexp_replace(sql_column, '\[(.+?)\]', to_char(some_date, '\1'))
from my_table;
Could you please help?
There is no way to parse ALL the possible date formats. For example, if you see '01/11/2017' in a varchar field you cannot say if it refers to November 1st or January 11th.
Said that, you can use a common table expression to choose the best pattern and then use it to convert the string value to date. For example:
select * from
(select
case
when REGEXP_LIKE(col2, '^[0-9]{2}/[0-9]{2}/[0-9]{4}$') then 'DD/MM/YYYY'
when REGEXP_LIKE(col2, '^[0-9]{14}$') then 'YYYYMMDDHH24MISS'
end pattern, table1.*
from table1) x
where to_date(x.col2, x.pattern) = to_date('01/11/2017','DD/MM/YYYY')
This approach would probably lead to a full table scan so it is far from being efficient. If the original table is large, I advice creating a materialized view with the converted date to improve performance.
You'll need a bit of dynamic SQL to solve this problem.
I do not present a complete solution, but this should give you a hint how to approach it.
Let's approach it bottom up.
What you actually need is a REPLACE statement, that transforms you SQL text in the required form with the paramater date.
This could be for your example this statement for teh first example (parameter date is 30.11.2017)
select replace(sql_column, '[DD-MON-YYYY]','30-NOV-2017') from my_table;
If you run the first statement on your first row you get the expected result:
select col1 from table1 where col2 = to_date('30-NOV-2017', 'DD-MON-YYYY');
So how to get those REPLACE statements. One possibility is to write a PL/SQL function.
The function has two parameters - the original SQL string and teh parameter date.
Using regexp you scrap the date format mask.
With dynamic SQL (EXECUTE IMMEDIATE) you format you parameter DATE as string with propper format.
Finally the REPLACE statement is returned.
create or replace function format_date(i_txt IN VARCHAR2, i_date DATE) return VARCHAR2 is
v_date_format VARCHAR2(4000);
v_form_date VARCHAR2(4000);
v_param VARCHAR2(4000);
v_form VARCHAR2(4000);
v_sql VARCHAR2(4000);
BEGIN
v_param := regexp_substr(i_txt, '\[(.+?)\]');
v_date_format := replace(replace(v_param,'[',null),']',null);
v_sql := 'select to_char(:d,'''||v_date_format||''') as my_dt from dual';
execute immediate v_sql into v_form_date using i_date;
v_form := 'select replace(sql_column, '''||v_param||''','''||v_form_date||''') from my_table';
return (v_form);
END;
/
NOTE that I handle only the first date mask in the string, you'll need to loop on all occcureces to get correct the second example!

SELECT command not being recognized for some reason.

For some reason, every time I try to run this, there is any error saying that the SQL statement at line 4, column 3 (SELECT) has been ignored. Also says, "YEAR": Invalid Identifier. Year is another column that exists on the same form. I am trying to make a column that displays the YEAR with a hyphen like for example this: "17-".
DECLARE
TERRA_NUMBER VARCHAR2(40);
BEGIN
SELECT CONCAT(YEAR , '-' )
INTO TERRA_NUMBER FROM DUAL;
RETURN TERRA_NUMBER;
END;
This is too long for a comment.
First, there is no YEAR variable in Oracle. Perhaps you intend TO_CHAR(sysdate, 'YYYY').
Second, an anonymous programming block does not return a value. So, RETURN is inappropriate.
If this is part of a function or stored procedure you should show the entire definition.
Maybe you can create FindYear function.
CREATE OR REPLACE FUNCTION FindYear RETURN VARCHAR2
IS
TERRA_NUMBER VARCHAR2(40);
BEGIN
SELECT CONCAT(TO_CHAR(sysdate, 'YYYY') , '-' )
INTO TERRA_NUMBER FROM DUAL;
RETURN(TERRA_NUMBER);
END;
/

Oracle Procedure error (PLS-00428)

This is the error message: PLS-00428: an INTO clause is expected in this SELECT statement. Meanwhile, this is the procedure for testing displaying the system date:
CREATE OR REPLACE
PROCEDURE "TEST_PROCEDURE"
AS
BEGIN
SELECT SYSDATE FROM DUAL;
END;
In the first place I don't need to use that INTO Oracle is insisting for me to do. Is there other way around beside using a cursor (I've seen it here https://stackoverflow.com/a/6029963/1983024)? I think it should not be like that, this does run normally just like in MS SQL without using INTO or cursor.
In the first place I don't need to use that INTO Oracle is insisting
for me to do.
The fact is, Oracle is correct: you do need to use an INTO to take the return value.
After all, if you want to display the result of the query you're going to need a variable to put it in first.
you can write
CREATE OR REPLACE
PROCEDURE "TEST_PROCEDURE"
AS
BEGIN
for r_row in ( SELECT SYSDATE s FROM DUAL)
dbms_output.put_line(r_row.s);
end loop;
END;
or you have to have a variable.
CREATE OR REPLACE
PROCEDURE "TEST_PROCEDURE"
AS
v_Date date;
BEGIN
SELECT SYSDATE into v_date FROM DUAL;
dbms_output.put_line(v_date );
END;
output format is dictated by your NLS_DATE_FORMAT setting, or you can be explicit like to_char(v_date, 'dd-mm-yyyy') etc.
Finally found a solution to the output I want (based on your responses) :D
CREATE OR REPLACE
PROCEDURE "TEST_PROCEDURE"
RET_DATE CHAR(10);
BEGIN
SELECT TO_CHAR(SYSDATE, 'MM/DD/YYYY') INTO RET_DATE FROM DUAL;
DBMS_OUTPUT.PUT_LINE(RET_DATE);
END;
This displays the SYSDATE with format of MM/DD/YYYY. Still, thanks for the replies and ideas (mostly #Jeffrey Kemp). Oracle just lengthens what MS SQL can normally do in one line :D
You can use like
CREATE OR replace PROCEDURE Test_procedure
IS
date CHAR(10);
BEGIN
SELECT To_char(SYSDATE, 'MM/DD/YYYY')
INTO date
FROM dual;
dbms_output.Put_line(date);
END;
it will return date into char format.
If you want to get date into date format just declare the date type variable then assign the sysdate value INTO that variable.Then use DBMS_OUTPUT.PUT_LINE(variable) to print the DATE.
If you wanted to do it in one line, you could also use:
CREATE OR replace PROCEDURE Test_procedure
IS
BEGIN
dbms_output.put_line(to_char(sysdate, 'MM/DD/YY'));
END;

How to return today's date to a variable in Oracle

I want to do this:
DECLARE #today as smalldatetime
SELECT #today = GetDate()
But i need an oracle translation
Oracle uses SYSDATE, and there's the ANSI standard CURRENT_TIMESTAMP (supported by both SQL Server and Oracle, besides others) to get the current date & time.
v_today DATE;
SELECT SYSDATE
INTO v_today
FROM DUAL;
...would be the equivalent to the TSQL you posted. Oracle uses the INTO clause for populating variables, where the variable data type must match the column position in the SELECT clause.
While not a strict translation, I prefer the following construction in Oracle:
v_today date; -- needs to go where variables are declared
v_today := sysdate; -- used where code is run.
Or even:
v_today date := sysdate;