Reading Oracle boolean filed dbms_utility.is_cluster_database in statement - oracle

I'd like to read boolean field from Oracle Database (11g), but I'm unable to do so, probably due to Oracle not fully supporting boolean data format.
Field I'm interessted in is dbms_utility.is_cluster_database.
Working statement:
set serveroutput on;
BEGIN
IF dbms_utility.is_cluster_database THEN
dbms_output.put_line('true');
ELSE
dbms_output.put_line('false');
END IF;
END;
This statement is working fine, however I need it as SQL query, like SELECT 'someValue' from dual;
I've tried:
SELECT dbms_utility.is_cluster_database FROM DUAL; fails with message "ORA-06553: PLS-382: expression is of wrong type"
SELECT CAST(dbms_utility.is_cluster_database AS INT) FROM DUAL; fails with same message
SELECT sys.diutil.bool_to_int(dbms_utility.is_cluster_database) from DUAL; fails with same message
SELECT CASE WHEN (dbms_utility.is_cluster_database) THEN 1 ELSE 0 END AS MY_BOOLEAN_COLUMN FROM DUAL; fails with message "SQL Error: ORA-00920: invalid relational operator"
I'm out of ideas how it can be fixed.
Problem is definitely not related to database access rights (since "dbms_output" solution works). Also, other fields from dbms_utility can be read using simple SELECT dbms_utility.<something> from dual;, eg. SELECT dbms_utility.get_endianness FROM DUAL;

i guess it's not possible to read boolean values in SQL, but you can write a wrapper function which would analyze that boolean and return varchar2/int/number.
alternatively, in your particular case you can do:
select value from v$parameter where name='cluster_database';

As suggest #MaxU you can create wrapper function.
create or replace function is_cluster_database return number is
begin
return sys.diutil.bool_to_int(dbms_utility.is_cluster_database);
end is_cluster_database;
And then used it like this
select is_cluster_database from dual;
Of course, result be number type.
is_cluster_database
0

Related

Raise an error if a subquery returns no result

In DB2 it is possible to raise an error if a subquery returns no results with the help of coalesce and the raise_error scalar function. But how can this be done in oracle?
I checked scalar functions so far, but there is no raise error function.
example for db2 (note: the subquery needs to be replaced by something meaningful...):
SELECT
COALESCE(
(SELECT 1 FROM SYSIBM.SYSDUMMY1 LIMIT 0),
RAISE_ERROR('70NUL', 'Value is missing'))
FROM
SYSIBM.SYSDUMMY1;
UPDATE 1:
The use case is about finding a matching value in another table during an export of millions of records. The idea is to raise an error if there is no matching value so it is detected early and not afterwards.
The way you describe it it sounds as if you need to mark a number of records based on whenever some values exist in a table. If PLSQL is an option you can just use the no_data_found exception:
invalid_data CONSTANT NUMBER := -70;
DECLARE
l_var NUMBER;
BEGIN
SELECT 1
INTO l_var
FROM dual
WHERE 1 <> 1;
EXCEPTION WHEN no_data_found THEN
/* do your updating or error handling */ RAISE_APPLICATION_ERROR(invalid_data ,'Value is missing');
END;
You can use RAISE_APPLICATION_ERROR feature of oracle to resolve your problem. You can declare a procedure and define when to raise the exception in that procedure. Simply call the procedure to execute your task and it will raise the error whenever your given condition staisfies.
For knowing in details, please see the trapping user defined exceptions section of oracle documentation with example.
In Oracle, you'd use similar query:
SQL> select coalesce((select dummy from dual where 1 = 2), 'Value is missing') result from dual;
RESULT
----------------
Value is missing
SQL> select coalesce((select dummy from dual where 1 = 1), 'Value is missing') result from dual;
RESULT
----------------
X
SQL>
I don't speak MS SQL Server so I can't comment it.
Alternative to #Gnqz solution is to write a user function wrapper around raise_application_error() in conjunction with coalesce.
CREATE OR REPLACE FUNCTION raise_error
RETURN NUMBER
IS
BEGIN
raise_application_error(-70, 'Mapping value is missing');
RETURN(0);
END;
select coalesce((select 5 AS result from dual fetch first 1 row only), raise_error()) AS result from dual;

Oracle PL/SQL SELECT INTO clause thinks it needs another INTO

I have a simple test function where I'm passing in a specific ID (the primary key of the table I'm selecting from), and computing a simple function on it and the parameters.
The skeleton code and test:
create or replace function test(id varchar2, area float) return float is
theRow forest%ROWTYPE;
begin
select * into theRow from forest where Forest_No = id;
return area / theRow.Area;
end;
begin
select test('1', 16000) from dual;
end;
The output:
[2019-10-14 21:19:10] [65000][6550] ORA-06550: line 2, column 5:
[2019-10-14 21:19:10] PLS-00428: an INTO clause is expected in this SELECT statement
I am at a loss for what to do here, as far as I can tell the documentation and examples use the same order and syntax. I have tried moving the into clause to the end as in Postgresql, but that did not work.
What have I missed here?
Issue is in calling statement.
Whenever select statement is used in plsql block it must have into clause to assign return value to variable.
You should remove begin and end from your calling code:
--begin -- remove this
select test('1', 16000) from dual;
--end; -- remove this
Or if you want to use it in plsql block then add into clause:
Declare
Area_ float(precision);
begin
select test('1', 16000) into area_ from dual;
-- use area_ in your code wherever required
dbms_output.put_line('area: ' || area_);
end;
Cheers!!

How to Declare, Populate and Use a Variable using Oracle PL/SQL

I swear this has been asked so many times previously, yet I cannot seem to apply other examples to my use case:
First things first, this query will be executed as part of an Informatica SQL Source Qualifier, and in some circumstances, be passed-through from an SQL Server OpenQuery statement, so please be mindful of this, and
that SQL Plus will not be used be used; Oracle SQL Developer is used only for code development.
My history is primarily SQL Server & Teradata, but as the title suggests, I now have a requirement where I need to declare, populate and use a variable in Oracle, all within the same procedure. Not SP, so no In/Out declarations
In SQL Server, this code will work as expected (line numbers added for clarity):
1. Declare #MaxDate Int
2.
3. With f_data (cal_period) As (Select 201904 As cal_period)
4.
5. Select #MaxDate = Max(cal_period) From f_data
6.
7. Select
8. Case
9. When (#MaxDate%100) < 12 Then #MaxDate+1
10. Else (#MaxDate+100) - ((#MaxDate%100)-1)
11. End As dt
Line 1: These are YYYYMM date periods defined as int
Line 3: I am using an inline view (CTE) here for illustration, and to
make it easier for you to copy and paste, but in reality, this is
actually a physical control table, so would not normally be visible in the
script.
Line 5: Populates the parameter (SQL Server prefixes parameters with
the at symbol) with the single-value resultset
Line 7-11: Is simply the logic to progress the period by one, the
percentage-mark in SQL Server is the Modulus function, Oracle is
written as Mod(#MaxDate,100)
For those unfamiliar with SQL Server, it does not need a reference table such as Dual ("Sys.Dual") in order to execute the query, such that for Oracle a "From Dual" statement is necessary on the missing Line 12
My requirement is essentially a carbon-copy of the above T-SQL, so I need to declare a one-time use variable, to populate that variable with the results of an SQL query, and then to use this variable in a transformation - the result of which is captured to an Informatica and SSIS variable for later use.
So far, I have tried declaring a variable, this seemed to work (by which I mean it didn't return an error):
Declare MaxPeriod Int;
Begin
Select 201904 Into MaxPeriod From Dual;
End;
And populating from an SQL statement is also showing as successfully completed:
Declare MaxPeriod Int;
Begin
Select Max(MaxPeriodVal) Into MaxPeriod From CtrlTable;
End;
Although I can't seem to get beyond this to actually test the variable as put.line statements fail, as do simple Case checks:
Declare MaxPeriod Int;
Begin
Select 201904 Into MaxPeriod From Dual;
End;
Select
Case
When 201904 = MaxPeriod Then 'Match'
Else 'No Match'
End As dteChk
From Dual;
I have attempted to prefix the MaxPeriod in the check with a colon, and, to have prefixed,suffixed/both with an ampersand eg :MaxPeriod; &MaxPeriod; MaxPeriod&; &MaxPeriod&
All of which failed.
The basic issue is a variable scope problem. You're declaring MaxPeriod within the context of a PL/SQL anonymous block, so it will disappear (fall out of scope) when the block ends on line 4.
You could put your entire query inside the PL/SQL block, but there's not an easy way to return an entire result set from a PL/SQL block, so I don't think you want that.
I don't know how your Oracle driver handles native queries, but this might work:
var MaxPeriod number; -- bind variable declared as global scope for this script
Begin -- one of several ways to assign values to bind variables
:MaxPeriod := 201904;
End;
/
Select
Case
When 201904 = :MaxPeriod Then 'Match'
Else 'No Match'
End As dteChk
From Dual;
If the var syntax doesn't work for you to declare a SQL bind variable, then you may have to look into some other way of passing a bind variable for the query string. You could probably pass a null value (for a number datatype, anyway) and then overwrite it in the SQL script.
Alternately, in your original example code, I think I'd use a CTE or an inline view instead of a variable anyway.
With f_data As (Select 201904 As cal_period from dual)
Select
Case
When Mod(MaxDate,100) < 12 Then MaxDate+1
Else (MaxDate+100) - (Mod(MaxDate,100)-1)
End As dt
from (Select Max(cal_period) as MaxDate From f_data) mp
You can use substitution variable using define in sql*plus as following.
Define MaxPeriod := 201904
Select
Case
When &MaxPeriod = MaxPeriod Then 'Match'
Else 'No Match'
End As dteChk
From Dual;
Cheers!!

Select Statement in oracle procedure

I can't able to create a select statement in oracle procedure. Please help me to create this.
Now I create the insert,update.delete statement in a procedure but i can't create a select statement. Please help me to create the select statement using cursor.
c_dbuser OUT SYS_REFCURSOR
ELSIF (TYPE_ =1) THEN
OPEN c_dbuser FOR
SELECT * FROM tbl_discount_master ;
CLOSE c_dbuser;
END IF;
call procedure_name(xx,xx,xx,1);
how can i get the selected value using call procedure statement.
In addition to the other suggestion, you have this solution when you are getting exactly one row.
DECLARE
myvar1 mytable.mycolumn1%TYPE;
myvar2 mytable.mycolumn2%TYPE;
BEGIN
SELECT mycolumn1, mycolumn2
INTO myvar1, myvar2
FROM mytable
WHERE …;
END;
This will throw an exception if there is no selected row (NO_DATA_FOUND) or if there is more than one row (TOO_MANY_ROWS).
The difference between select and the insert/update/delete is that you need to select into some structure, either one or more variables or a rowtype variable.
Avoid explicit cursors whenever possible in favour of the faster, less verbose and less error prone implicit cursor.
eg.
for cur_my_query in
select column1,
column2,
...
from ...
where ...
loop
refer here to cur_my_query or my_query.column1 etc
end loop

IF-ELSE issue in Select Statement in Oracle

I have following query in SQL Server which I am trying to convert to Oracle 11g.
IF '[Param.1]' = 'S' OR '[Param.1]' = 'T' THEN
select * from ULQUEUE
END IF
But when I write the same query in Oracle, it gives error stating Invalid SQL Statement. So how do I incorporate IF-ELSE in Select Statement in Oracle?
You are converting a T-SQL statement. The equivalent in Oracle is an anonymous PL/SQL block.
However, PL/SQL is a bit more demanding than T-SQL. It requires selecting rows into variables. If the query will return more than one row we need to define a collection variable or use a cursor.
Depending on your requirements you may enbd up with something like this:
begin
if ( &&param1 = 'S' or &&param1 = 'T' ) then
for lrec in ( select * from ulqueue ) loop
do_something;
end loop;
end if;
end;
/
I agree this looks like more work than T-SQL, but PL/SQL is a proper programming language with a lot more functionality. Find out more.

Resources