Validating decimals in a column - oracle sqldeveloper - oracle

Im trying to come up with a test that validates decimals in a particular column (with 220000 records). For example for column A there shouldn't be any values with more decimals than 2, 1 is also ok.
for example :
Column A (datatype varchar)
48528.64
135082.54
5249.1
I tried with round function but than I get an error saying invalid number.
Also I would like to be able to change the number of decimals I put in the test to use with different columns
For example
Its 1 big table with all columns having datatype VARCHAR2(2000 char)
examples for columns:
total amount (value should have no more than 2 decimals)
48528.64
135082.54
349.1123 (not OK)
Balance (value should have no more than 2 decimals)
45428.64
1895082.11
5249.1483 (not OK)
Loan (value should have no more than 6 decimals)
100.64
88999.11654
1000.178875554 (not OK)
For each column I want to set up a seperate test that checks if the value is within the number of decimals allowed. So preferable a select statement with a where clause where I can adjust the numbers of decimals so I end up with all records having 1 or 2 decimals, or all the records that have more than 2 decimals

Invalid number error is due to the fact that you have something that isn't a number in that column, so when you apply numeric function to it, Oracle complains. That's what you get when you store numbers as strings. Don't do that.
Anyway, here's one option which shows what you might try to do: as these are strings, calculate number of digits right of the decimal point.
SQL> select * From test;
A
--------------------
48528.64 -- OK
135082.54 -- OK
5249.1 -- OK
1.2345 -- not OK
-25.553 -- not OK
SQL> select *
2 from test
3 where length(regexp_substr(a, '\d+$')) > 2;
A
--------------------
1.2345
-25.553
SQL>
If there are several columns and you'd like to check each of them using a separate table which holds allowed number of decimals, then you could do something like this:
SQL> with
2 big (total, balance, loan) as
3 (select 48528.64 , 45428.64 , 100.64 from dual union all
4 select 135082.54 , 1895082.11 , 88999.11654 from dual union all
5 select 349.1123 , 5249.1483, 1000.178875554 from dual
6 ),
7 septest (tdec, bdec, ldec) as
8 (select 2, 2, 6 from dual)
9 select
10 b.total,
11 case when length(regexp_substr(b.total,'\d+$')) > s.tdec then 'Not OK'
12 else 'OK'
13 end total_ok,
14 --
15 b.balance,
16 case when length(regexp_substr(b.balance,'\d+$')) > s.bdec then 'Not OK'
17 else 'OK'
18 end balance_ok,
19 --
20 b.loan,
21 case when length(regexp_substr(b.loan,'\d+$')) > s.ldec then 'Not OK'
22 else 'OK'
23 end loan_ok
24 from big b cross join septest s;
TOTAL TOTAL_OK BALANCE BALANCE_OK LOAN LOAN_OK
---------- ---------- ---------- ---------- ---------- ----------
48528,64 OK 45428,64 OK 100,64 OK
135082,54 OK 1895082,11 OK 88999,1165 OK
349,1123 Not OK 5249,1483 Not OK 1000,17888 Not OK
SQL>
Lines #1 - 8 represent sample data; you already have that. Query you actually need begins at line #9.

Related

Allow multiple values from SSRS in oracle

I have a query that gets contract_types 1 to 10. This query is being used in an SSRS report to filter out a larger dataset. I am using -1 for nulls and -2 for all.
I would like to know how we would allow multiple values - does oracle concatenate the inputs together so '1,2,3' would be passed in? Say we get select -1,0,1 in SSRS, how could we alter the bottom query to return values?
My query to get ContractTypes:
SELECT
ContractType,
CASE WHEN ContractType = -2 THEN 'All'
WHEN ContractType = -1 THEN'Null'
ELSE to_Char(ContractType)
END AS DisplayFigure
FROM ContractTypes
which returns
ContractType DisplayFig
-1 Null
0 0
1 1
2 2
3 3
4 4
5 5
6 6
7 7
8 8
9 9
10 10
This currently is only returning single values or all, not muliple values:
SELECT *
FROM Employee
WHERE NVL(CONTRACT_TYPE, -1) = :contract_type or :contract_type = -2
I'm assuming we want to do something like:
WHERE NVL(CONTRACT_TYPE, -1) IN (:contract_type)
But this doesn't seem to work.
Data in Employee
Name ContractType
Bob 1
Sue 0
Bill Null
Joe 2
In my report, I want to be able to select contract_type as -1(null),0,1 using the 'allow muliple values' checkbox. At the moment, I can only select either 'all' using my -2 value, or single contract types.
My input would be: contract type = -1,1,2
My output would be Bill, Bob, Joe.
This is how I'm executing my code
I use SSRS with Oracle a lot so I see where you're coming from. Thankfully, they work pretty well together.
First make sure the parameter is set to allow multiple values. This adds a Select All option to your dropdown so you don't have to worry about adding a special case for "All". You'll want to make sure the dataset for the parameter has a row with -1 as the Value and a friendly description for the Label.
Next, the WHERE clause would be just as you mentioned:
WHERE NVL(CONTRACT_TYPE, -1) IN (:contract_type)
SSRS automatically populates the values. There is no XML or string manipulation needed. Keep in mind that this will not work with single-value parameters.
If for some reason this still doesn't work as expected in your environment, there is another workaround you can use which is more universal and works even with ODBC connections.
In the dataset parameter properties, use an expression like this to concatenate the values into a single, comma-separated string:
="," + Join(Parameters!Parameter.Value, ",") + ","
Then use an expression like this in your WHERE clause:
where :parameter like '%,' + Column + ',%'
Obviously, this is less efficient because it most likely won't be using an index, but it works.
I don't know SSRS, but - if I understood you correctly, you'll have to split that comma-separated values list into rows. Something like in this example:
SQL> select *
2 from dept
3 where deptno in (select regexp_substr('&&contract_type', '[^,]+', 1, level)
4 from dual
5 connect by level <= regexp_count('&&contract_type', ',') + 1
6 );
Enter value for contract_type: 10,20,40
DEPTNO DNAME LOC
---------- -------------------- --------------------
20 RESEARCH DALLAS
10 ACCOUNTING NEW YORK
40 OPERATIONS BOSTON
SQL>
Applied to your code:
select *
from employee
where nvl(contract_type, -1) in (select regexp_substr(:contract_type, '[^,]+', 1, level)
from dual
connect by level <= regexp_substr(:contract_type, ',') + 1
)
If you have the comma separated list of numbers and then if you like to split it then, the below seems simple and easy to maintain.
select to_number(column_value) from xmltable(:val);
Inputs: 1,2,3,4
Output:
I guess I understood your problem. If I am correct the below should solve your problem:
with inputs(Name, ContractType) as
(
select 'Bob', 1 from dual union all
select 'Sue', 0 from dual union all
select 'Bill', Null from dual union all
select 'Joe', 2 from dual
)
select *
from inputs
where decode(:ContractType,'-2',-2,nvl(ContractType,-1)) in (select to_number(column_value) from xmltable(:ContractType))
Inputs: -1,1,2
Output:
Inputs: -2
Output:

Access other values ​in a trigger before save Oracle

Is it possible to access the previous values ​​that have not yet been stored in the database?
I have a table related to a particular module (MOD) which I will call table XA.
I can insert multiple records into XA simultaneously they are going to be inserted, I cannot change this fact.
For example, the following data is inserted in XA
ID | ParentId | Type | Name | Value
1 | 1 | 5 | Cost | 20000
2 | 1 | 9 | Risk | 10000
And I need in this case to insert / update a record in this same table. A calculated value
At the moment of executing the trigger, the value with the name of Cost for example is inserted first, and then the value of Risk.
When evaluating the Risk, I must have the ability to know what the Cost value is to make the calculation and insert the calculated record.
I tried to create a Package to which I would feed the data, but I still have the same problem.
create or replace PACKAGE GLOBAL
IS
PRAGMA SERIALLY_REUSABLE;
TYPE arr IS TABLE OF VARCHAR2 (32)
INDEX BY VARCHAR2 (50);
NUMB arr;
END GLOBAL;
//Using in trigger
GLOBAL.NUMB (:NEW.ID || '-' || :NEW.ParentId) := :NEW.Value;
BEGIN
IF :NEW.Type == 9 AND GLOBAL.NUMB (5 || '-' || :NEW.ParentId) IS NOT NULL
THEN
// calculate and insert record
ELSE IF :NEW.Type == 5 AND GLOBAL.NUMB (9 || '-' || :NEW.ParentId) IS NOT NULL
// calculate and insert record
END IF;
EXCEPTION
WHEN NO_DATA_FOUND
THEN
// NOT HAVE TWO INSERT TO SAME REGISTER
END;
Values ​​5 and 9 are for reference.
Both records are not always inserted, one or more can be inserted, even the calculated value can be imputed but must be replaced by the calculation.
And I can't create a view since there is an internal process that depends on this particular table.
Do you really really must store calculated value into a table? That's usually not the best idea as you have to maintain it in any possible case (inserts, updates, deletes).
Therefore, another suggestion: a view. Here's an example; my "calculation" is simple, I'm just subtracting cost - risk as I don't know what you really do. If calculation is very complex and should be run every time on a very large data set, yes - performance might suffer.
Anyway, here you go; see if it helps.
Sample data:
SQL> select * From xa order by parentid, name;
ID PARENTID TYPE NAME VALUE
---------- ---------- ---------- ---- ----------
1 1 5 Cost 20000
2 1 9 Risk 10000
5 4 5 Cost 4000
7 4 9 Risk 800
A view:
SQL> create or replace view v_xa as
2 select id,
3 parentid,
4 type,
5 name,
6 value
7 from xa
8 union all
9 select 0 id,
10 parentid,
11 99 type,
12 'Calc' name,
13 sum(case when type = 5 then value
14 when type = 9 then -value
15 end) value
16 from xa
17 group by parentid;
View created.
What does it contain?
SQL> select * from v_xa
2 order by parentid, type;
ID PARENTID TYPE NAME VALUE
---------- ---------- ---------- ---- ----------
1 1 5 Cost 20000
2 1 9 Risk 10000
0 1 99 Calc 10000
5 4 5 Cost 4000
7 4 9 Risk 800
0 4 99 Calc 3200
6 rows selected.
SQL>

oracle forms 12. how to display leading zero of decimal numbers

I wish to display decimal numbers (from a query) into text items.
if I set
:TXT_ITEM := '0,000123456789'
it works. But, if :TXT_ITEM is bound to a numeric table field, value is displayed as ,000123456789.
I'm trying to force format number on several triggers (post-change, when-new-record-instance, post-text...), unsuccessfully. On other hand, setting format_mask would force my DB value to a given number of decimal digits.
How can I get leading zero to be displayed?
See if any of these two options help.
Sample data:
SQL> create table test as
2 (select 12.34 col from dual union all
3 select 0.1234003 from dual union all
4 select -13.43432203 from dual union all
5 select 0.00012345221 from dual union all
6 select -0.002412428238234821 from dual
7 );
Table created.
SQL> desc test;
Name Null? Type
----------------------------------------- -------- ----------------------------
COL NUMBER
SQL> select col,
2 regexp_replace(col, '^(-?)([.,])', '\10\2') result1,
3 rtrim(to_char(col, 'fm90D999999999999999999999'), '.') result2
4 from test;
COL RESULT1 RESULT2
---------- ------------------------- -------------------------
12,34 12,34 12,34
,1234003 0,1234003 0,1234003
-13,434322 -13,43432203 -13,43432203
,000123452 0,00012345221 0,00012345221
-,00241243 -0,002412428238234821 -0,002412428238234821
SQL>
How would use it/them in Forms? Exactly like that - you'd e.g.
select regexp_replace(col, '^(-?)([.,])', '\10\2')
into :block.text_item
from your_table
where some_condition;
Seems the concerned numeric data in the table is of type
NUMBER(13,12)
in this case it's enough to set TXT_ITEMs Format Mask attribute within the Data part of Property Palette as
0D000000000000
with precision of 13 and scale of 12 values.
Considering the scale part is fixed, you can add more zeroes before D character depending on your column's precision value such as two zeroes before D are kept for NUMBER(14,12) or three zeroes for NUMBER(15,12).

Need specific number format in Oracle S9(15)V9(2)

I have a requirement to produce amount fields in zoned decimal format with this specific syntax below.
I don’t know if I need to create a function to handle this or if I can tweak the Oracle number format model. I’m thinking it might require some conditional formatting within a function due to the different requirement for number of digits between positive and negative. I will be performing this formatting on a couple of dozen data elements in the procedure so that might be another reason to use a function. Thoughts?
Requirement:
Amount should be represented by 17 characters (positive number) or 16 characters plus a “}” appended to the end (negative number).
Ex. 0.00 should show as 00000000000000000.
Ex. -935,560.00 should show as 00000000093556000}
Using Oracle 12c.
If I understood you correctly, the input is already formatted and its datatype is VARCHAR2. If that's so, then this might do the job:
SQL> with test (col) as
2 (select '0.00' from dual union all
3 select '25.34' from dual union all
4 select '-935,560.00' from dual
5 )
6 select col,
7 lpad(translate(col, 'x,.-', 'x'),
8 case when substr(col, 1, 1) = '-' then 16
9 else 17
10 end, '0') ||
11 case when substr(col, 1, 1) = '-' then '}'
12 else null
13 end result
14 from test;
COL RESULT
----------- --------------------
0.00 00000000000000000
25.34 00000000000002534
-935,560.00 0000000093556000}
SQL>
What does it do?
lines #1 - 5 - sample data
line #7 - translate removes minus sign, commas and dots
lines #7 - 10 - lpad pads the number (without characters from the previous step) with zeros up to the length of 16 (for negative values) or 17 (for positive values) characters
lines #11 - 13 - if it is a negative value, concatenate } to the end of the result string

Oracle plsql how to check if number has decimal points

Just started working with oracle using toad ide. trying to format the numbers from a table in specific format. the numbers come in from a variable in the table and I want to display the whole numbers as whole numbers and display floats as floats. So far, I can use trim(TO_CHAR (width,'999.999')) to display all numbers with decimal points.
For example: 123.5 will be displayed as 123.500 and 100 will be displayed as 100.000.
What I want to do is display for eg: 100 as 100.
Hope this is clear and I get a solution soon.
I'm using MOD for determining decimals.
select test_value, (case when mod(test_value,1) != 0 then 'DECIMAL' else 'NODECIMAL' END) IS_DECIMAL
from (select 1.5 test_value from dual
union all
select 100 test_value from dual) test_table
If your problem is about the way Toad shows numbers, you can follow the hints in the comments.
If the problem is about the way Oracle shows numbers, converting them to strings, maybe this can help:
SQL> select to_char(1.5, 'TM9') as num from dual union all
2 select to_char(100, 'TM9') from dual;
NUM
----------------------------------------------------------------
1,5
100
You find much more in the documentation
If you need a way to check whether a number has a decimal part or not, you can simply try:
SQL> with numbers(num) as (
2 select 1.5 from dual union all
3 select 100 from dual
4 )
5 select case
6 when floor(num) = num
7 then to_char(num, 'FM999999') || ' has not a decimal part'
8 else
9 to_char(num, 'FM9999D000') || ' has a decimal part'
10 end as checkString
11 from numbers;
CHECKSTRING
------------------------------
1,500 has a decimal part
100 has not a decimal part

Resources