how to add two parameters and get value in sql (convert code pl/sql to sql ) - sql

function CF_TOTAL_AMTFormula return Number is
begin
RETURN NVL(:AMOUNT,0)+ NVL(:CF_TAX,0);
end;
This function is created in PL/SQL and I want to create this function in SQL.

As OldProgrammer mentioned above, "SQL does not have user-defined functions". Maybe you just want to add two parameters together in SQL? It's pretty straightforward...
select NVL(:AMOUNT,0) + NVL(:CF_TAX,0) as CF_TOTAL_AMT from dual;

Well, SQL does allow inline functions, but they are implemented in PL/SQL so I'm not sure whether they meet your requirement:
with function cf_total_amtformula
( amount number, cf_tax number )
return number
as
begin
return nvl(amount,0) + nvl(cf_tax,0);
end;
select amount, cf_tax
, cf_total_amtformula(amount, cf_tax) as formula_result
from -- inline view to provide demo data:
( select 123 as amount, .2 as cf_tax from dual
union all
select 123, null from dual
union all
select null, .2 from dual )
(requires Oracle 12.1 or later.)
Obviously you could just use nvl(amount,0) + nvl(cf_tax,0) directly without defining any function, or define a column in a view etc.

Putting Bind parameters into a function definition doesn't work, and results in a PLS-00049: bad bind variable error. I think what you are looking for is this:
function CF_TOTAL_AMTFormula(AMOUNT number, CF_TAX number) return Number is
begin
RETURN NVL(AMOUNT,0)+ NVL(CF_TAX,0);
end;
Note that both AMOUNT and CF_TAX have had the leading colons : removed, and have been moved up to the function signature.
Once compiled with create or replace ... you can then call the function in SQL like so:
select CF_TOTAL_AMTFormula(121, 12.1) from dual;

select amount, cf_tax
, nvl(amount,0) + nvl(cf_tax,0)
from -- inline view to provide demo data:
( select 123 as amount, .2 as cf_tax from dual
union all
select 123, null from dual
union all
select null, .2 from dual )

Related

Oracle SQL: how to pass parameter to a function that is used in a view through a column in a view?

Let's say we have such view that uses function with hard-coded parameter:
CREATE OR REPLACE VIEW x AS
SELECT t.some_value
FROM table(function(p1 => '1')) t;
If I'd like to pass that parameter to a function through a view, what are possible options? Please mind that using global or context/bind variables is not an option. So far I've came up with an option to use a table that holds all available parameter values (keys) that could be passed to a view:
CREATE OR REPLACE VIEW x AS
SELECT st.input_param,
t.some_value
FROM some_table st
table(function(p1 => st.input_param)) t;
However, I am wondering if there are any other possible options?
You can't pass a parameter to a view but you can use the next alternative:
CREATE TYPE RECORDS_VARCHAR AS TABLE OF VARCHAR2(100);
create or replace function virtual_table( input_param number )
return RECORDS_VARCHAR
PIPELINED
is
begin
FOR a IN (
select '1' AS VALUE from dual where input_param = 2
UNION ALL
select '8' AS VALUE from dual
) loop
pipe row (a.VALUE);
end loop;
return;
end;
SELECT * FROM TABLE(virtual_table(2)); --1,8
SELECT * FROM TABLE(virtual_table(1)); --8

Search varchar2 for a format?

How do you query varchar2 for a format? Example is Varchar2 field containing date as mm/dd/yyyy '01/01/2015'. How would I find a date that was written as yyyy/mm/dd '2015/01/01' as I do not know the incorrectly formatted date so i can't literally search it. I just want to write where FIELD_1 like '####/##/##' but that obviously does not work.
Of course what you want to do works, if you use regular expressions:
where regexp_like(field_1, '^[0-9]{4}/[0-9]{2}/[0-9]{2}$')
As a side note: you should not be storing dates in the database as strings. You should be using dates instead.
Gordon's answer is probably good enough for what you need, but it may be an issue that the regular expression he gave you will match things like 9999/99/99 that are not dates.
If you really need to match dates -- and if the date is the entire value of the VARCHAR2 and not just embedded somewhere in it -- then a function can help.
In the below example, I create a function called safe_to_date that returns a NULL if the given VARCHAR2 value is not a date in the specified format.
CREATE OR REPLACE FUNCTION safe_to_date ( p_string VARCHAR2 ) RETURN DATE IS
BEGIN
RETURN to_date(p_string,'YYYY/MM/DD');
EXCEPTION
WHEN others THEN
RETURN NULL;
END;
with my_table AS
( SELECT '9999/99/99' /*invalid*/ my_column FROM dual UNION ALL
SELECT '2015/12/25' from dual UNION ALL
SELECT 'not a date at all' /*invalid*/ FROM dual UNION ALL
SELECT '11-NOV-1917' from dual UNION ALL
SELECT '2015*DEC*25' from dual UNION ALL
SELECT '2015/02/28' from dual UNION ALL
SELECT '2015/02/29' /*invalid*/ from dual)
SELECT *
FROM my_table
WHERE safe_to_date(my_column) IS NOT NULL;
Expected results:
25-DEC-2015
11-NOV-1917
25-DEC-2015
28-FEB-2015

PL/SQL - Returning a table from a function

I am creating a function that returns a table as a result. This function is basically doing comparison between two tables, and returns data set that if two tables contain different data.
P_min_id and p_max_id are ignorable, and will be implemented in the future once this function is working.
I modified the original code from http://www.adp-gmbh.ch/ora/plsql/coll/return_table.html. The error messages are commented in the following code.
create or replace function return_objects(
p_min_id in number,
p_max_id in number
)
return t_nested_table as
v_ret t_nested_table;
begin
select * // Error(8,7): PL/SQL: SQL Statement ignored
into
v_ret
from
(
select
*
from
(
select * from
(
select * from SCHEMA.TEST
minus
select * from SCHEMA.TEST_1
)
union all
select * from
(
select * from SCHEMA.TEST_1
minus
select * from SCHEMA.TEST
)
)
)
return v_ret;
end return_objects;
It would be appreciated if you can fix my code, but I want to know why this code should not work. Please give me some keyword, so that I can research. or relevant website for reference would be also appreciated.
Add a semicolon after the end of the SQL statement and use bulk collect to populate the nested table. Here's a working example:
create or replace type t_nested_table is table of varchar2(100);
create or replace function return_objects(
p_min_id in number,
p_max_id in number
)
return t_nested_table as
v_ret t_nested_table;
begin
select *
bulk collect into v_ret
from
(
select 'A' from dual union all
select 'B' from dual
);
return v_ret;
end;
/
select return_objects(1,2) from dual;
UPDATE
Based on the question edits there is also a privilege issue. Your user probably has access to the tables through a role, but to create a function those privileges should be granted directly to your user.

SQL: how do I find if the contents of a varchar column are numeric?

One of the columns in my table is a varchar that is supposed to contain only numeric values (I can't change the definition to a number column). Thus my SQL query:
select to_number(col1) from tbl1 where ...
fails because for some row the contents of the column are not numeric.
What's a select query I can use to find these rows ?
I'm using an Oracle database
I'm looking for something like a is_number function.
There is no native "isnumeric" function in oracle, but this link shows you how to make one:
http://www.oracle.com/technetwork/issue-archive/o44asktom-089519.html
CREATE OR REPLACE FUNCTION isnumeric(p_string in varchar2)
RETURN BOOLEAN
AS
l_number number;
BEGIN
l_number := p_string;
RETURN TRUE;
EXCEPTION
WHEN OTHERS THEN
RETURN FALSE;
END;
/
I don't disagree that the best solution is to follow Tom Kyte's examples others have linked to already. However, if you just need something that is SQL only because you unfortunately do not have the relationship with your DBA to add pl/sql functions to your schema you could possibly leverage regular expressions to meet a basic need. Example:
select '234', REGEXP_SUBSTR('234','^\d*\.{0,1}\d+$') from dual
union all
select 'abc', REGEXP_SUBSTR('abc','^\d*\.{0,1}\d+$') from dual
union all
select '234234abc', REGEXP_SUBSTR('234234abc','^\d*\.{0,1}\d+$') from dual
union all
select '100.4', REGEXP_SUBSTR('100.4','^\d*\.{0,1}\d+$') from dual
union all
select '-100.4', REGEXP_SUBSTR('-100.4','^\d*\.{0,1}\d+$') from dual
union all
select '', REGEXP_SUBSTR('','^\d*\.{0,1}\d+$') from dual
Below is the output of the above:
INPUT RESULT
234 234
abc -
234234abc -
100.4 100.4
-100.4 -
Read this: http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:1794145000346577404
You may need to decide for yourself what is numeric.
Oracle will happily convert character strings in scientific notation (eg '1e10') to numbers, but it will baulk at something like '1,000' (because of the comma).

Oracle and SQLServer function evaluation in queries

Let's say I have a function call on a select or where clause in Oracle like this:
select a, b, c, dbms_crypto.hash(utl_raw.cast_to_raw('HELLO'),3)
from my_table
A similar example can be constructed for MS SQLServer.
What's the expected behavior in each case?
Is the HASH function going to be called once for each row in the table, or DBMS will be smart enough to call the function just once, since it's a function with constant parameters and no side-effects?
Thanks a lot.
The answer for Oracle is it depends. The function will be called for every row selected UNLESS the Function is marked 'Deterministic' in which case it will only be called once.
CREATE OR REPLACE PACKAGE TestCallCount AS
FUNCTION StringLen(SrcStr VARCHAR) RETURN INTEGER;
FUNCTION StringLen2(SrcStr VARCHAR) RETURN INTEGER DETERMINISTIC;
FUNCTION GetCallCount RETURN INTEGER;
FUNCTION GetCallCount2 RETURN INTEGER;
END TestCallCount;
CREATE OR REPLACE PACKAGE BODY TestCallCount AS
TotalFunctionCalls INTEGER := 0;
TotalFunctionCalls2 INTEGER := 0;
FUNCTION StringLen(SrcStr VARCHAR) RETURN INTEGER AS
BEGIN
TotalFunctionCalls := TotalFunctionCalls + 1;
RETURN Length(SrcStr);
END;
FUNCTION GetCallCount RETURN INTEGER AS
BEGIN
RETURN TotalFunctionCalls;
END;
FUNCTION StringLen2(SrcStr VARCHAR) RETURN INTEGER DETERMINISTIC AS
BEGIN
TotalFunctionCalls2 := TotalFunctionCalls2 + 1;
RETURN Length(SrcStr);
END;
FUNCTION GetCallCount2 RETURN INTEGER AS
BEGIN
RETURN TotalFunctionCalls2;
END;
END TestCallCount;
SELECT a,TestCallCount.StringLen('foo') FROM(
SELECT 0 as a FROM dual
UNION
SELECT 1 as a FROM dual
UNION
SELECT 2 as a FROM dual
);
SELECT TestCallCount.GetCallCount() AS TotalFunctionCalls FROM dual;
Output:
A TESTCALLCOUNT.STRINGLEN('FOO')
---------------------- ------------------------------
0 3
1 3
2 3
3 rows selected
TOTALFUNCTIONCALLS
----------------------
3
1 rows selected
So the StringLen() function was called three times in the first case. Now when executing with StringLen2() which is denoted deterministic:
SELECT a,TestCallCount.StringLen2('foo') from(
select 0 as a from dual
union
select 1 as a from dual
union
select 2 as a from dual
);
SELECT TestCallCount.GetCallCount2() AS TotalFunctionCalls FROM dual;
Results:
A TESTCALLCOUNT.STRINGLEN2('FOO')
---------------------- -------------------------------
0 3
1 3
2 3
3 rows selected
TOTALFUNCTIONCALLS
----------------------
1
1 rows selected
So the StringLen2() function was only called once since it was marked deterministic.
For a function not marked deterministic, you can get around this by modifying your query as such:
select a, b, c, hashed
from my_table
cross join (
select dbms_crypto.hash(utl_raw.cast_to_raw('HELLO'),3) as hashed from dual
);
For SQL server, it will be evaluated for every single row.
You will be MUCH better off by running the function once and assigning to a variable and using the variable in the query.
short answer....it depends.
If the function is accessing data ORACLE does not know if it is going to be the same for each row, therefore, it needs to query for each. If, for example, your function is just a formatter that always returns the same value then you can turn on caching (marking it as Deterministic) which may allow for you to only do the function call once.
Something you may want to look into is ORACLE WITH subquery:
The WITH query_name clause lets you
assign a name to a subquery block. You
can then reference the subquery block
multiple places in the query by
specifying the query name. Oracle
optimizes the query by treating the
query name as either an inline view or
as a temporary table
I got the quoted text from here, which has plenty of examples.