I'm giving a functionality which works on 12c and has JSON related operations.
but when database is 11g the JSON queries should be skipped. Need if condition for this but this should consider future approach as in it should be able to handle next oracle version.
E.g JSON supported in 12c and above but not below
with v$version I can compare string in if condition but it is static
current implementation as follows
SELECT substr(banner, 1, 19)banner
into x_version
FROM v$version
WHERE banner LIKE 'Oracle Database 12c%';
IF x_version = 'Oracle Database 12c' THEN ...
You could use conditional compilation, based on dbms_db_version values:
declare
$if not dbms_db_version.ver_le_11_2 $then
l_var number;
$end
begin
$if dbms_db_version.ver_le_11_2 $then
null;
$else
select json_value('{x:42}', '$.x') into l_var from dual;
dbms_output.put_line('12c+: ' || l_var);
$end
end;
/
On 11gR2 this just gets:
PL/SQL procedure successfully completed.
On 12c it gets:
12c+: 42
PL/SQL procedure successfully completed.
Wrap any variable declarations that are only relevant to 12c+ operations, and any code that you only want to call in 12c and above, in conditions.
Of course, this will only work on version 11gR2 or above; if you need to be able to run (without doing anything) on 11gR1 then change the check to ver_le_11. Even that won't be recognised if you try to run on a 10g or earlier database though.
If you need to handle other earlier versions, you can check the version number directly (as #Wernfried showed):
declare
$if dbms_db_version.version >= 12 $then
l_var number;
$end
begin
$if dbms_db_version.version >= 12 $then
select json_value('{x:42}', '$.x') into l_var from dual;
dbms_output.put_line('12c+: ' || l_var);
$else
null;
$end
end;
/
The $else null; part is only needed because I have nothing else in my block - I would get PLS-00103: Encountered the symbol "END" ... without it (in 11g or earlier). If there is other unconditional code then that isn't necessary, though it may still be clearer to include it.
What about this?
DECLARE
ver number;
BEGIN
DBMS_OUTPUT.PUT_LINE ( 'DBMS_DB_VERSION.VERSION = ' || DBMS_DB_VERSION.VERSION );
DBMS_OUTPUT.PUT_LINE ( 'DBMS_DB_VERSION.RELEASE = ' || DBMS_DB_VERSION.RELEASE );
ver := (10*DBMS_DB_VERSION.VERSION + DBMS_DB_VERSION.RELEASE) / 10;
DBMS_OUTPUT.PUT_LINE ( 'ver = ' || ver );
end;
DBMS_DB_VERSION.VERSION = 12
DBMS_DB_VERSION.RELEASE = 1
ver = 12.1
Or you may use
SELECT VALUE
FROM NLS_DATABASE_PARAMETERS
WHERE PARAMETER = 'NLS_RDBMS_VERSION';
Related
I am trying to run the sub-query based on version in Oracle. Since oracle released the new version 21c have to modify the query in that way.
I would like to check if the version is 19c then take the value from sys.aud$ else take the value AUDSYS.AUD$UNIFIED.
select version,
CASE
WHEN version <= '19.0.0.0.0' THEN (select * from sys.aud$)
ELSE
(select * from AUDSYS.AUD$UNIFIED)
END version_group
from v$Instance;
I am getting ORA-00913: too many values as the error.
If you are using PL/SQL then you can use conditional compilation. For example:
DECLARE
v_cur SYS_REFCURSOR;
BEGIN
OPEN v_cur FOR
select v.version, s.*
from v$Instance v
CROSS JOIN
$IF DBMS_DB_VERSION.VER_LE_19
$THEN
sys.aud$ s
$ELSE
AUDSYS.AUD$UNIFIED s
$END
;
END;
/
I want to create an alias from an select result.I've tried to use oracle dynamic query but doesn't working.Here is my sql:
declare
v_a varchar2(50);
sql_smt varchar2(200);
begin
select TO_CHAR('#'||TO_CHAR(sysdate-30,'yyyymmdd')||'-'||TO_CHAR(sysdate+2,'yyyymmdd')) INTO v_a from dual;
sql_smt :='SELECT sysdate as :1 FROM dual';
execute immediate sql_smt using v_a;
end;
I want to reach to an result like in the photo.
Thanks for any help!
As you've tagged this for SQL Developer you could use (ab)use substitution variables for this; in your worksheet do:
column x_title new_value y_title noprint;
select TO_CHAR('#'||TO_CHAR(sysdate-30,'yyyymmdd')||'-'||TO_CHAR(sysdate+2,'yyyymmdd'))
as x_title
from dual;
set verify off
select sysdate as "&y_title" from dual;
which when you run as a script (F5) produces this in the Script Output window:
<blank lines ...>
#20190126-
----------
2019-02-25
and then if you run the last line again as a statement (control-enter) the Query Result window shows it as you wanted, from the image in your question.
You could also use the column command which makes the output in the Script Output closer to what you wanted when run as a script:
column sysdate heading &y_title
select sysdate from dual;
#20190126-20190227
------------------
2019-02-25
but then when run as a statement the Query Results window doesn't honour that heading.
Note that this is all client-specific functionality, not SQL - it will work in SQL Developer, and the script versions will work in SQL*Plus and SQLcl, but not in other clients (unless they have tried to feature-match SQL*Plus to some extent).
If you aren't only going to be viewing the results in one of those clients but actually want to end up, say, pulling them into an application over JDBC or whatever, then other solutions would be more appropriate. Generating a ref cursor with the column as the name you want would be fairly simple. But that's not what you've asked for...
OK, since you asked in a comment, you can open a ref cursor in an anonymous block:
var rc refcursor
declare
l_alias varchar2(50);
begin
select TO_CHAR('#'||TO_CHAR(sysdate-30,'yyyymmdd')||'-'||TO_CHAR(sysdate+2,'yyyymmdd'))
into l_alias
from dual;
open :rc for 'SELECT sysdate as "' || l_alias || '" FROM dual';
end;
/
PL/SQL procedure successfully completed.
print rc
#20190127-
----------
2019-02-26
or without the local variable:
var rc refcursor
begin
open :rc for 'SELECT sysdate as "'
|| TO_CHAR('#'||TO_CHAR(sysdate-30,'yyyymmdd')||'-'||TO_CHAR(sysdate+2,'yyyymmdd'))
|| '" FROM dual';
end;
/
PL/SQL procedure successfully completed.
print rc;
#20190127-
----------
2019-02-26
Again var[iable] and print are client-specific commands; and I don't think there's a way to get the results in the Query Results grid with this approach. But you can use the same anonymous block approach from other clients or applications; e.g. from JDBC you could have a statement as:
String sql = "begin open ? for 'SELECT sysdate as \"'"
+ "|| TO_CHAR('#'||TO_CHAR(sysdate-30,'yyyymmdd')||'-'||TO_CHAR(sysdate+2,'yyyymmdd'))"
+ "|| '\" FROM dual'; end;";
and then bind the ? parameter placeholder as a cursor type before executing. That probably isn't very useful though as you'd have to examine the metadata to find the column alias anyway, and you could generate it on the application side using the application language tools (e..g Java date manipulation).
You could also create a function that returns a ref cursor, which you could then call from a plain query (instead of an anonymous block), which would allow you to see it in the Query Results grid - possibly with an extra step to show the cursor result. But you made not need that extra level of code or want another object to be created in your DB.
Would something like this work?
declare
col_hdr varchar2(50);
sys_date varchar2(26);
sql_smt varchar2(200);
begin
select TO_CHAR('#'||TO_CHAR(sysdate-30,'yyyymmdd')||'-'||TO_CHAR(sysdate+2,'yyyymmdd')) INTO col_hdr from dual;
sql_smt :='SELECT sysdate ' || ' as "' || col_hdr || '" FROM dual';
dbms_output.put_line(sql_smt);
execute immediate sql_smt into sys_date;
dbms_output.put_line('done');
end;
I have to call oracle SQL statement inside my project.
All connection related stuff is done, but my tool does not capture the output parameter executed by oracle.
Hence I need alter this query to return p_num value in a select statement.
i.e. the table which has 1 column ('p_num') with column name called 'Result' and which has only one row which is p_num value.
Following is the sql statement which currently gives output value with help of dbms_output.put_line
DECLARE
p_num varchar2(4000);
message varchar2(4000) ;
BEGIN
p_num := MyFunction();
dbms_output.put_line('Message : ' || p_num) ;
END;
What I want is p_num value in a SELECT statement so that I can capture specific column inside my bpm tool.
You can directly call the function in the SELECT statement.
1) First way is to do it VIA plain SQL
SELECT MyFunction FROM DUAL;
2) Second way is PLSQL but i will not recommend it unless its unavoidable
set serveroutput on;
declare
lv_var VARCHAR2(100);
lv_out_param VARCHAR2(100);
BEGIN
lv_var:=MyFunction(lv_out_param);
dbms_output.put_line(lv_var||' '||lv_out_param);
END;
/
This is one of those situations where you get an unhelpful error message back from Oracle.
My situation is as follows: I'm dynamically creating a view in PL/SQL. I build a string and use EXECUTE IMMEDIATE to create the view. The string is so long that I use a CLOB to store it.
When I run the code below in TOAD I get the unhelpful
ORA-00907: missing right parenthesis error.
Manually creating the view in TOAD (without the EXECUTE IMMEDIATE) gives no problems. My feeling is that the length of the string is a factor here as I've successfully created views with shorter strings (and also by using to_char() instead of dbms_lob.substr(), however to_char() only works with smaller clobs).
The total string length is 13775. (Obviously I've edited the line below where I build the string.) This is an Oracle 10g database on Linux.
declare
lv_sql CLOB;
begin
lv_sql := ' CREATE OR REPLACE FORCE VIEW my_view.....';
EXECUTE IMMEDIATE dbms_lob.substr(lv_sql, 14765, 1 );
end;
As Klas has said, you should be able to use VARCHAR2(32767) for your variable declaration but if you find that this is not quite enough, you could just use more than one VARCHAR2 variable to hold the various parts of the view statement and then issue them to the EXECUTE IMMEDIATE statement.
An AskTom answer here demonstrates:
http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:6161200355268
Says:
You have indicated that the max string length for execute immediate
is 32K.
We are using execute immediate to create generated packages and we are
currently passing it > 35000 chars
by execute immediate v_myvc1 || my_vc2
vc1 and vc2 are 32 k varchar2 vars. whose combined length is currently
35000
All on 8.1.7
My Question is what is the maximum length for the execute immediate
string cause I was worried it was 32k and we are already over it, and
I'm not sure when I'm going to hit the wall.
Tom Kyte responds:
Followup March 5, 2003 - 6pm Central time zone:
interesting -- never would have thought to do it that way.
That appears to work -- will it hit a wall? not sure, I would never
have gone over 32k.
looks like it can go pretty large:
ops$tkyte#ORA817DEV> declare
2 l_str1 long := 'select /* ' || rpad( '*', 20000, '*' ) || ' */ * ';
3 l_str2 long := 'from /* ' || rpad( '*', 15000, '*' ) || ' */ dual';
4 l_str3 long := '/* ' || rpad( '*', 32000, '*' ) || ' */ ';
5 l_result dual.dummy%type;
6 begin
7 execute immediate l_str1||l_str2||l_str3||l_str3||l_str3||' d' into l_result;
8 dbms_output.put_line( l_result );
9 end;
10 /
PL/SQL procedure successfully completed.
Though this was on an Oracle 8i database instance I would be very surprised if the ability to daisy-chain the VARCHAR2 variables had been dropped in later revisions. Unfortunately I can't test it as I don't have a 10g instance available to hand at the moment.
I'm trying to call an Oracle stored proc using SQL Developer. The proc outputs results using a sys_refcursor. I right click in the proc window which brings up the Run PL/SQL window. When I choose the proc I want it creates all the input params etc for me. Below is the code I'm using to try and loop through the sys_refcursor and output the results, but I'm getting an error on the 'v_rec v_Return%rowtype;' line :
ORA-06550: line 6 column 9:
PLS-00320: the declaration of the type of this expression is incomplete or malformed.
ORA-06550: line 6 column 9:
PL/SQL: Item ignored
vendor code 6550
I found the looping code on a couple of other websites and it seems to be the way to do it but it's not working for me no matter what I try. Another question - on the DBMS_OUTPUT.PUT_LINE('name = ' || v_rec.ADM) am I referencing the v_rec correctly i.e. is v_rec."column_name" the correct way??
I'm not that used to Oracle and have never used SQL plus. Any suggestions appreciated.
DECLARE
P_CAE_SEC_ID_N NUMBER;
P_PAGE_INDEX NUMBER;
P_PAGE_SIZE NUMBER;
v_Return sys_refcursor;
v_rec v_Return%rowtype;
BEGIN
P_CAE_SEC_ID_N := NULL;
P_PAGE_INDEX := 0;
P_PAGE_SIZE := 25;
CAE_FOF_SECURITY_PKG.GET_LIST_FOF_SECURITY(
P_CAE_SEC_ID_N => P_CAE_SEC_ID_N,
P_PAGE_INDEX => P_PAGE_INDEX,
P_PAGE_SIZE => P_PAGE_SIZE,
P_FOF_SEC_REFCUR => v_Return
);
-- Modify the code to output the variable
-- DBMS_OUTPUT.PUT_LINE('P_FOF_SEC_REFCUR = ');
loop
fetch v_Return into v_rec;
exit when v_Return%notfound;
DBMS_OUTPUT.PUT_LINE('name = ' || v_rec.ADM);
end loop;
END;
Your problem is here:
v_Return sys_refcursor;
v_rec v_Return%rowtype;
v_Return is a cursor variable and has no specific structure (list of columns), so v_Return%rowtype is not a valid record structure to declare v_rec. It is even possible for different calls to the procedure to return cursors with different structures.
You know what you are expecting the structure of the returned cursor to be (but Oracle doesn't) so you need to explicitly define the appropriate record structure e.g.
type t_row is record (empno number, ename varchar2(30));
v_rec t_row;
You need a strongly typed ref cursor to be able to define it as a %ROWTYPE.
Example here
#Tony Andrews thanks for this it gave me a better idea where I was going wrong. Still having problems though - here's a shortened version of my proc. It's a bit complex in that it's selecting all fields from a subquery and 2 other values:
open p_fof_sec_refcur for
SELECT *
FROM(
SELECT securities.*, rownum rnum, v_total_count
FROM
(
SELECT
CFS.CAE_SEC_ID,
CFS.FM_SEC_CODE,
...
FROM
CAEDBO.CAE_FOF_SECURITY CFS
INNER JOIN caedbo.CAE_DATA_SET_ELEMENT CDSE_STAT
ON (CDSE_STAT.DATA_SET_ELEMENT_ID = CFS.APPR_STATUS)
...
WHERE APPR_STATUS = NVL(p_appr_status, APPR_STATUS)
...
)securities
)
WHERE rnum between v_pgStart and v_pgEnd;
I explicitly defined the output structure as below to match the return fields from the proc but I'm still getting an error:
v_Return sys_refcursor;
type t_row is record (CAE_SEC_ID NUMBER,FM_SEC_CODE VARCHAR2(7),...rnum number, v_total_count number);
v_rec t_row;
The error I get is
ORA-06504: PL/SQL: Return types of Result Set variables or query do not match
ORA-06512: at line 45
I'm just wondering is the "rownum rnum, v_total_count" part tripping me up. I'm pretty sure I have all the other fields in the output structure correct as I copied them directly from the proc.