Check Oracle Version and Then run a sub-query - oracle

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;
/

Related

trying to add an agent (not allowing duplicate last names). Initial total sales should be zero

I am receiving the following error when trying to compile and execute. I am having issues how to figure this out.
14/7 PL/SQL: Statement ignored
14/10 PLS-00204: function or pseudo-column 'EXISTS' may be used inside a SQL statement only
Errors: check compiler log
CREATE OR REPLACE PROCEDURE AddAgent(
p_Agent_Fname IN Agent.Agent_Fname%TYPE,
p_Agent_Lname IN Agent.Agent_Lname%TYPE,
p_Agent_Address IN Agent.Agent_Address%TYPE,
p_Agent_Tsales IN Agent.Agent_Tsales%TYPE,
p_Agent_Salary IN Agent.Agent_Salary%TYPE)
IS
p_ErrorCode number; --USED FOR ERROR CHECKING
p_ErrorMsg Varchar2(200);
p_CurrentUser Varchar2(100);
BEGIN
IF EXISTS
(SELECT * FROM Agent WHERE Agent_Lname = p_Agent_Lname) THEN
dbms_output.put_line('Failure');
ELSE
INSERT INTO Agent (Agent_Fname, Agent_Lname, Agent_Address, Agent_Tsales, Agent_Salary)
SELECT p_Agent_Fname, p_Agent_Lname, p_Agent_Address, 0, p_Agent_Salary
from Dual;
COMMIT;
dbms_output.put_line('Success');
END IF;
END;
As you were told, you can't use EXISTS out of the SELECT statement. Therefore, you'll have to check for existence in the AGENT table elsewhere.
Here's one option you might consider. Note that I've also rewritten the INSERT INTO statement - there's no need to SELECT FROM DUAL, you already have all those values.
CREATE OR REPLACE PROCEDURE AddAgent(
p_Agent_Fname IN Agent.Agent_Fname%TYPE,
p_Agent_Lname IN Agent.Agent_Lname%TYPE,
p_Agent_Address IN Agent.Agent_Address%TYPE,
p_Agent_Tsales IN Agent.Agent_Tsales%TYPE,
p_Agent_Salary IN Agent.Agent_Salary%TYPE)
IS
p_ErrorCode number; --USED FOR ERROR CHECKING
p_ErrorMsg Varchar2(200);
p_CurrentUser Varchar2(100);
l_cnt number; --> newly added
BEGIN
-- check whether something exists in a table
select count(*)
into l_cnt
from dual
where exists (select null
from agent
where agent_lname = p_agent_lname
);
IF l_cnt > 0 then
dbms_output.put_line('Failure');
ELSE
INSERT INTO Agent
(Agent_Fname, Agent_Lname, Agent_Address, Agent_Tsales, Agent_Salary)
VALUES
(p_Agent_Fname, p_Agent_Lname, p_Agent_Address, 0, p_Agent_Salary);
COMMIT;
dbms_output.put_line('Success');
END IF;
END;
/

Oracle version check before running queries

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';

WM_CONCAT with DISTINCT Clause - Compiled Package versus Stand-Alone Query Issue

I was writing some program that uses the WM_CONCAT function. When I run this query:
SELECT WM_CONCAT(DISTINCT employee_id)
FROM employee
WHERE ROWNUM < 20;
It works fine. When I try to compile the relatively same query in a package function or procedure, it produces this error: PL/SQL: ORA-30482: DISTINCT option not allowed for this function
FUNCTION fetch_raw_data_by_range
RETURN VARCHAR2 IS
v_some_string VARCHAR2(32000);
BEGIN
SELECT WM_CONCAT(DISTINCT employee_id)
INTO v_some_string
FROM employee
WHERE ROWNUM < 20;
RETURN v_some_string;
END;
I realize WM_CONCAT is not officially supported, but can someone explain why it would work as a stand alone query with DISTINCT, but not compile in a package?
Problem is that WM_CONCAT is stored procedure written on pl/sql.
There is a open bug #9323679: PL/SQL CALLING A USER DEFINED AGGREGRATE FUNCTION WITH DISTINCT FAILS ORA-30482.
Workaround for problems like this is using dynamic sql.
So if you wrap your query in
EXECUTE IMMEDIATE '<your_query>';
Then it should work.
But as OldProgrammer has suggested already, you better avoid using this WM_CONCAT at all.
PL/SQL will not let you to use distinct in an aggregated function, and this issue shows that the SQL-engine and the PL/SQL-engine do not use the same parser.
One of the solutions to this problem is to use sub query as below,
SELECT WM_CONCAT(employee_id)
INTO v_some_string
FROM (select DISTINCT employee_id
FROM employee)
WHERE ROWNUM < 20;
Another solution is to use dynamic SQL as Nagh suggested,
FUNCTION fetch_raw_data_by_range
RETURN VARCHAR2 IS
v_some_string VARCHAR2(32000);
v_sql VARCHAR2(200);
BEGIN
v_sql :='SELECT WM_CONCAT(DISTINCT employee_id)
FROM employee
WHERE ROWNUM < 20';
execute immediate v_sql INTO v_some_string;
RETURN v_some_string;
END;

Oracle "into" clause in Oracle version below 11g

I have pl/sql anonymous block like below
declare
v_count pls_integer := 0;
begin
select count(1) from product_component_version
into v_count
where product like '%Enterprise%';
if v_count = 0 then
raise program_error;
end if;
exception
when program_error then
raise_application_error (-20001, 'This is valid for Oracle Enterprise Edition only!');
end;
When I try to execute the above,I am getting the below error
ORA-06550: line 5, column 5:
PL/SQL: ORA-00933: SQL command not properly ended
Which is nothing but for "into v_count" statement.
As per my understanding the syntax is wrong and when I changed that statemnt like below it is working fine.
select count(1) into v_count
from product_component_version
where product like '%Enterprise%';
I have tested this in "Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit".
But the original script is available in all our older versions of our product.
I would like to know the syntax in original script is supported in older oracle versions?
Or can you please let me know any information on this which can answer my confusion?
Thanks,
Vijay
With a test block:
declare
x dual.dummy%type;
begin
select dummy from dual into x;
end;
/
In Oracle 9iR2 (9.2.0.8 on Solaris), 10gR2 (10.2.0.5 on Solaris) and 11gR2 (11.2.0.3 on Linux) I get exactly the same error:
select dummy from dual into x;
*
ERROR at line 4:
ORA-06550: line 4, column 28:
PL/SQL: ORA-00933: SQL command not properly ended
ORA-06550: line 4, column 5:
PL/SQL: SQL Statement ignored
I don't believe it has ever been supported the way you had it, though I don't have an 8i or earlier database to test against.
You said 'the original script is available in all our older versions of our product', but would it actually ever have been run, and if so can you identify an exact version it didn't raise an error against?
At least not from 8i onwards:
http://www.oracle.com/pls/tahiti/tahiti.tabbed?section=49135
Even i don't thing so about select dummy from dual into x;
try this:
declare
v_count pls_integer := 0;
begin
select count(1) into v_count from product_component_version
where product like '%Enterprise%';
if v_count = 0 then
raise program_error;
end if;
exception
when program_error then
raise_application_error (-20001, 'This is valid for Oracle Enterprise Edition only!');
end;

SSIS Execute SQL Task throwing ORA-01008: not all variables bound error

I have an Execute SQL task (SQL 2008) where I'm using two SSIS variables to interact with an Oracle database:
DECLARE ParamTest number; TempOutputRun varchar(255);
ParamTest := ?;
TempOutputRun := ?;
BEGIN
IF ParamTest = 0 THEN
SELECT CAST(OUTPUT_RUN_ID AS VARCHAR(15)) AS OUTPUT_RUN_ID FROM GL_EXTRACT_STATUS WHERE STATUS='NEW' ORDER BY OUTPUT_RUN_ID ASC;
ELSE
SELECT TempOutputRun AS OUTPUT_RUN_ID FROM DUAL;
END IF
;
END;
I'm getting the error ORA-01008 on execution and I'm not sure why. Both variables have values, and are set to the correct datatypes with Parameter Names in mapping of 0 and 1 respectively. The ELSE part of this statement should be the one tripped by the current conditions I'm testing under.
Anyone have any ideas? I'm stumped (and quite frustrated, to be perfectly honest).
Thanks!
Valkyrie
Without knowing much about SSIS, it seems to me you need to select...into in your code:
SELECT CAST(OUTPUT_RUN_ID AS VARCHAR(15)) AS OUTPUT_RUN_ID
INTO some_var
FROM ...
WHERE ...
and
SELECT TempOutputRun AS output_run_id
INTO another_var
FROM dual;
I don't quite get why the ora-01008. Running the select from dual in a PL/SQL block as written gives me an ora-06550.
You have to use the following syntax
BEGIN
DECLARE
.....
BEGIN
.....
END;
END;

Resources