I am using Oracle, and I need to perform some mathematic calculations where I need TO_CHAR().
But it is not comparing the values.
Here is sample below.
IF TO_CHAR(V_APP_FAIR_RENT, '99,9999') > TO_CHAR(v_ACT_RENTAMT, '99,9999')
THEN
V_HIGHER_RENT_PREMIUM := 0;
dbms_output.put_line('Higher Rental premium 0 :' || V_HIGHER_RENT_PREMIUM);
ELSE
V_HIGHER_RENT_PREMIUM := v_ACT_RENTAMT / V_AMTINMONTH;
V_HIGHER_RENT_PREMIUM := V_HIGHER_RENT_PREMIUM * V_NOOFDAYSINMONTH;
V_HIGHER_RENT_PREMIUM := V_HIGHER_RENT_PREMIUM - V_APP_FAIR_RENT;
V_HIGHER_RENT_PREMIUM := ROUND(V_HIGHER_RENT_PREMIUM / V_NOOFOPCO);
dbms_output.put_line('Higher rental premium 1 :' || V_HIGHER_RENT_PREMIUM);
END IF;
The values for both comparison is below.
V_APP_FAIR_RENT = 7455 and v_ACT_RENTAMT = 10928
Technically with the above comparision it should go in IF condition, but actually it goes in ELSE condition.
Please suggest where I am going wrong.
If as you say your original columns are strings (why?), and your examples do not appear to include group or decimal characters, then why not use to_number with default formatting to compare the numeric values?
IF to_number(V_APP_FAIR_RENT) > to_number(V_ACT_RENTAMT)
THEN
V_HIGHER_RENT_PREMIUM := 0;
dbms_output.put_line('Higher Rental premium 0 :' || V_HIGHER_RENT_PREMIUM);
ELSE
V_HIGHER_RENT_PREMIUM := v_ACT_RENTAMT / V_AMTINMONTH;
V_HIGHER_RENT_PREMIUM := V_HIGHER_RENT_PREMIUM * V_NOOFDAYSINMONTH;
V_HIGHER_RENT_PREMIUM := V_HIGHER_RENT_PREMIUM - V_APP_FAIR_RENT;
V_HIGHER_RENT_PREMIUM := ROUND(V_HIGHER_RENT_PREMIUM / V_NOOFOPCO);
dbms_output.put_line('Higher rental premium 1 :' || V_HIGHER_RENT_PREMIUM);
END IF;
as #pmdba said, why are you converting what is already a number(is it?), for comparison?
If you execute the query:
select TO_CHAR(7455 , '99,9999'), TO_CHAR(10928, '99,9999') from dual
the result is the strings: "7455" "1,0928".
One has a thousands separator and the other does not. so you are not comparing numerical values, and the string representation will not work for compare in this case.
If you still are bent on conversion, you need to remove the comma separator:
select TO_CHAR(7455 , '999999'), TO_CHAR(10928, '999999') from dual
maybe you can edit your question to show how those variables are defined to determine what you are trying to accomplish.
Related
Is it possible to limit whole number and decimal number for an item in Oracle APEX?
If "limit" means to set their minimum and maximum value, then yes - in item's properties:
As you commented, it is about number of characters. In that case, create a validation, e.g. function that returns error text such as
declare
l_max_len_whole number := 5;
l_max_len_decimals number := 2;
--
l_len_whole number;
l_len_decimals number;
begin
l_len_whole := length(regexp_substr(:P1_ITEM, '\d+'));
l_len_decimals := case when :P1_ITEM = trunc(:P1_ITEM) then 0
else length(regexp_substr(:P1_ITEM - trunc(:P1_ITEM), '\d+$')
end;
if l_len_whole > l_max_len_whole then
return 'No more than ' || l_max_len_whole || ' whole digits';
elsif l_len_decimals > l_max_len_decimals then
return 'No more than ' || l_max_len_decimals || ' decimal digits';
end if;
end;
When I click the button for the first time, my selected column is sorted. When I click for the second time, it will sort in reverse.How can I do this?
Note: My program consists of dummy block. No data blocks
declare
cursor c is
select *
from muhasebe.doviz_takip
where UPPER(fatura_no) LIKE
NVL('%' || UPPER(:giris.sorgulama) || '%', UPPER(fatura_no))
order by fatura_no asc;
begin
go_block('XDOVIZ_TAKIP');
clear_block;
first_record;
for r in c loop
:FATURA_NO := r.fatura_no;
:ACIKLAMA := r.aciklama;
:YUKLEME_TAR := r.yukleme_tar;
:VARIS_TAR := r.varis_tar;
:TUTAR := r.tutar;
next_record;
end loop;
first_record;
end;
This is the code I can sort once
One option is to create a global variable (or a parameter), two cursors (one for each sorting) and IF-THEN-ELSE which decides which cursor to use, depending on global variable's value.
Something like this:
DECLARE
CURSOR c_asc IS
SELECT *
FROM muhasebe.doviz_takip
WHERE UPPER (fatura_no) LIKE
NVL ('%' || UPPER ( :giris.sorgulama) || '%',
UPPER (fatura_no))
ORDER BY fatura_no ASC;
CURSOR c_desc IS
SELECT *
FROM muhasebe.doviz_takip
WHERE UPPER (fatura_no) LIKE
NVL ('%' || UPPER ( :giris.sorgulama) || '%',
UPPER (fatura_no))
ORDER BY fatura_no DESC;
BEGIN
GO_BLOCK ('XDOVIZ_TAKIP');
CLEAR_BLOCK;
FIRST_RECORD;
:global.sort := NVL ( :global.sort, 'ASC');
IF :global.sort = 'DESC'
THEN
FOR r IN c_asc
LOOP
:FATURA_NO := r.fatura_no;
:ACIKLAMA := r.aciklama;
:YUKLEME_TAR := r.yukleme_tar;
:VARIS_TAR := r.varis_tar;
:TUTAR := r.tutar;
NEXT_RECORD;
END LOOP;
:global.sort := 'ASC';
ELSIF :global.sort = 'ASC'
THEN
FOR r IN c_desc
LOOP
:FATURA_NO := r.fatura_no;
:ACIKLAMA := r.aciklama;
:YUKLEME_TAR := r.yukleme_tar;
:VARIS_TAR := r.varis_tar;
:TUTAR := r.tutar;
NEXT_RECORD;
END LOOP;
:global.sort := 'DESC';
END IF;
FIRST_RECORD;
END;
Perhaps you could try to make it "smarter" (as this is pretty much dummy - repeating more or less the same code twice), but - this is simple and easy to maintain.
One another approach would be converting it to a database block by creating a view named v_doviz_takip such as
CREATE OR REPLACE VIEW v_doviz_takip AS
SELECT *
FROM muhasebe.doviz_takip
and setting the Query Data Source Name of the block xdoviz_takip to this
and adding a WHERE clause
UPPER(fatura_no) LIKE NVL('%' || UPPER(:giris.sorgulama) || '%', UPPER(fatura_no))`
to the block. Then add a line
SET_BLOCK_PROPERTY('xdoviz_takip',order_by, 'fatura_no');
to the WHEN-NEW-FORM-INSTANCE trigger.
And convert your current code block to this one :
DECLARE
v_ord VARCHAR2(25) := GET_BLOCK_PROPERTY('XDOVIZ_TAKIP',order_by);
BEGIN
GO_BLOCK ('XDOVIZ_TAKIP');
CLEAR_BLOCK;
IF v_ord = 'fatura_no' THEN v_ord := v_ord||' DESC'; ELSE v_ord := 'fatura_no' END IF;
SET_BLOCK_PROPERTY('XDOVIZ_TAKIP',order_by, v_ord);
EXECUTE_QUERY;
FIRST_RECORD;
END;
this way, it will sort descendingly by fatura_no for the first, and ascendingly for the second attempts
, or just converting the current IF clause to IF v_ord != 'fatura_no' ... would reversely change the behaviour.
The code below is looking for a string to match a column name. However I would like to search for a string to match Data (meaning, search on each existing column and row from all views - not column names). I want the results to show me all Views Names that contain that string on their Data. Hope this makes sense.
begin
dbms_output.put_line('Owner View name');
dbms_output.put_line('------------------------------ -------------------------------');
for r in (
select v.owner, v.view_name, v.text
from all_views v
where v.owner <> 'SYS'
)
loop
if lower(r.text) like '%my_String%' then
dbms_output.put_line(rpad(r.owner,31) || r.view_name);
end if;
end loop;
end;
I suggest you at least review some of the Oracle documentation. Your statement "Oracle SQL... i am using Oracle SQL Developer" indicates a lack of understanding. So lets clear some of that up. You are actually using 3 separate software tools:
Oracle SQL - all access to data being stored in your Oracle database.
Oracle Pl/SQL - the programming language, which tightly integrates with but is still separate from SQL. This is the language in which your script is written.
Oracle SQL Developer - an IDE within which you develop, run, etc run your Pl/SQL scripts and/or SQL statements.
Now as for your script. The syntax is fine and it will run, successfully retrieving all non sys owned views and printing the names of those containing the specified search string. However, as it currently stands it'll never find a match. Your match statement attempts to match a lower case string to a string that contains the character 'S' (upper case). There will never be a match. Also, keep in mind that within LIKE the underscore (_) is a single character wild card. You may need to escape it as "like '%my_ ...'". With these in mind we come to:
REVISED
The requirement to actually find the string in view columns completely changes things from your original query. Although the title does suggest that was actually the initial desire. What you want to accomplish is much more complex and cannot be done in SQL alone; it requires PL/SQL or an external language code. The reason is that you need run select but you don't know against what nor what columns nor even how many columns area needed. For that you need to identify the view, isolate the viable columns and generate the appropriate SQL dynamically then actually execute that sql and check the results.
Two approaches come to mind: Parse the view to extract the columns (something I would even consider doing in PL/SQL) or join ALL_VIEWS with ALL_TAB_COLUMNS (All table columns). That we'll do. The majority of the code will be constructing the SQL and the necessary error handling dynamic SQL essentially forces on you. I've created this a a procedure with 2 parameters: the target string, and the schema.
create or replace procedure find_string_in_view(
schema_name_in varchar2
, target_string_in varchar2
)
is
--- set up components for eventual execution
k_new_line constant varchar2(2) := chr(10);
k_base_statement constant varchar2(50) :=
q'!select count(*) from <view_name> where 1=1 and !' || k_new_line;
k_where_statement constant varchar2(50) :=
q'! <column_name> like '%<target>%' !' || k_new_line;
k_limit_statement constant varchar2(20) :=
' ) and rownum < 2';
k_max_allowed_errors constant integer := 3;
--- cursor for views and column names
cursor c_view_columns is
(select av.owner,av.view_name , atc.column_name
, lead(atc.column_name) over (partition by av.view_name order by atc.column_id) next_col
, lag(atc.column_name) over (partition by av.view_name order by atc.column_id) prev_col
from all_views av
join all_tab_columns atc
on ( atc.owner = av.owner
and atc.table_name = av.view_name
)
where av.owner = upper(schema_name_in)
and atc.data_type in
('CHAR', 'NCHAR', 'VARCHAR2','NVARCHAR2','VARCHAR','NVARCHAR')
) ;
--- local variables
m_current_view varchar2(61);
m_sql_errors integer := 0;
m_where_connector varchar(2);
m_sql_statement varchar2(4000);
-- local helper function
function view_has_string
return boolean
is
l_item_count integer := 0;
begin
execute immediate m_sql_statement into l_item_count;
return (l_item_count > 0);
exception
when others then
dbms_output.put_line(rpad('-',61,'-') || k_new_line);
dbms_output.put_line('Error processing:: ' || m_current_view);
dbms_output.put_line('Statement::' || k_new_line || m_sql_statement);
dbms_output.put_line(sqlerrm);
m_sql_errors := m_sql_errors + 1;
if m_sql_errors >= k_max_allowed_errors
then
raise_application_error(-20199,'Maximun errors allowed reach. Terminating');
end if;
return false;
end view_has_string;
begin -- MAIN --
dbms_output.put_line('Owner View name');
dbms_output.put_line('------------------------------ -------------------------------');
for rec in c_view_columns
loop
if rec.prev_col is null
then
m_current_view := rec.owner || '.' || rec.view_name;
m_sql_statement := replace(k_base_statement,'<view_name>',m_current_view);
m_where_connector := ' (';
end if;
m_sql_statement := m_sql_statement || m_where_connector
|| replace(k_where_statement,'<column_name>',rec.column_name);
m_where_connector := 'or' ;
if rec.next_col is null
then
m_sql_statement := replace(m_sql_statement,'<target>',target_string_in);
m_sql_statement := m_sql_statement || k_limit_statement;
if view_has_string
then
dbms_output.put_line(rpad(rec.owner,31) || rec.view_name);
end if;
end if;
end loop;
end find_string_in_view;
select v.owner, v.view_name, v.text
from all_views v
where v.owner <> 'SYS' and lower(v.text) like '%my_String%'
one SQL do this?
I have a table in which there is a primary key named CODE of Type VARCHAR(3). The problem is that all the available values from 000,001 .... 999 are used in different records. As the field CODE is in varchar format so we can have alphabets along with digits.
Is there any algorithm or function in plsql through which we can uniformly generate unique keys of length 3 which includes alphabets as well. Note that we cannot change the field size as it is referenced in so many other tables.
what about this solution
generate alpha-numeric code based on oracle sequence
please check code
declare
l_val number := 255; -- SQN_TMP_01.nextval;
l_base number := 62; -- 00azAZ
l_base_str varchar2(62) := '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
l_res number;
l_final varchar2(100);
begin
loop
-- init numberic value
l_val := SQN_TMP_01.nextval;
l_final := null;
dbms_output.put_line(l_val);
-- convert value to alphanumeric code
loop
l_res := mod(l_val, l_base);
l_final := substr(l_base_str, l_res + 1, 1) || l_final;
exit when l_val - l_res = 0;
l_val := trunc((l_val - l_res) / l_base);
dbms_output.put_line('res = ' || l_res || ' l_val = ' || l_val || ' final: "' || l_final || '"');
end loop;
dbms_output.put_line('check final: "' || l_final || '"');
-- exclude full numeric result as already used
exit when trim(translate(l_final, '0123456789', ' ')) is not null;
end loop;
dbms_output.put_line('final string: "' || l_final || '"');
end;
You should almost certainly migrate your field to an integer type. If that's impossible then it should be possible to convert to a larger char field as bpgergo suggests.
If you're really, really stuck with a 3 character limit you could use to_char(id, 'xxx') to convert to hex, as in: Oracle: How do I convert hex to decimal in Oracle SQL?
This would give you up to 4096 entries. It should be possible (but more complex) to use base64 (up to 262,144 entries), or go up to base 128 (2,097,152), or just use the whole field as a 3 byte unsigned integer if you don't care about the raw data being printable characters (16,777,216).
I have an implementation of the jaro-winkler algorithm in my database. I did not write this function. The function compares two values and gives the probability of match.
So jaro(string1, string2, matchnoofchars) will return a result.
Instead of comparing two strings, I want to send one string with a matchnoofchars and then get a result set with the probability higher than 95%.
For example the current function is able to return 97.62% for jaro("Philadelphia","Philadelphlaa",9)
I wish to tweak this function so that I am able to find "Philadelphia" for an input of "Philadelphlaa". What kind of changes do I need to make for this to happen?
I am using Oracle 9i.
Do you have a list of words that contain words like "Philadelphia"?
And who did write that function?
Oracle has package utl_match for fuzzy text comparison: http://download.oracle.com/docs/cd/E14072_01/appdev.112/e10577/u_match.htm
Can't you do
select w1.word
from words w1
where jaro(w1.word,'Philadelphlaa', 9) >= 0.95
?
This will select 'Philadelphia' if that word is present in table words.
A little dirty but faster (untested!).
Let's assume first three characters are the same and length is also approximately the same.
DECLARE
CURSOR citynames(cp_start in varchar2, cp_length in number) IS
SELECT city FROM table_loc_master where statecode = 'PQ'
and city like cp_start||'%'
and length(city) between cp_length -2 and cp_length +2;
CURSOR leasecity IS
SELECT city FROM table_loc where State = 'PQ'
MINUS
SELECT to_char(city) city FROM table_loc_master where statecode = 'PQ';
xProb NUMBER(10,8);
BEGIN
FOR x_rec IN leasecity
LOOP
FOR y_rec IN citynames(substr(x_rec.city,1,3), length(x_rec.city))
LOOP
xProb := jwrun(x_rec.city,y_rec.city,length(y_rec.city));
If xProb > 0.97 Then
DBMS_OUTPUT.PUT_LINE('Source : ' || x_rec.city || ' Target: ' || y_rec.city );
End if;
END LOOP;
END LOOP;
END;
DECLARE
CURSOR citynames IS
SELECT city FROM table_loc_master where statecode = 'PQ';
CURSOR leasecity IS
SELECT city FROM table_loc where State = 'PQ'
MINUS
SELECT to_char(city) city FROM table_loc_master where statecode = 'PQ';
xProb NUMBER(10,8);
BEGIN
FOR x_rec IN leasecity
LOOP
FOR y_rec IN citynames
LOOP
xProb := jwrun(x_rec.city,y_rec.city,length(y_rec.city));
If xProb > 0.97 Then
DBMS_OUTPUT.PUT_LINE('Source : ' || x_rec.city || ' Target: ' || y_rec.city );
End if;
END LOOP;
END LOOP;
END;