Hai,
i have a problem with number format.i'm using oracle.
I have a number field in database.But when i retreive it i need to be seen as floating point number
For example:
while retreiveing,now i got the result as 200 DR (DR for Debit,it is given manually).
Now i need to get the result as 200.00 DR as the result.
How can i solve this?Can any one help me?
You can use the TO_CHAR function to explicitely format data:
SQL> SELECT to_char(200.00, 'fm999G999G990D00') FROM dual;
TO_CHAR(200.00,'FM999G999G990D
------------------------------
200.00
Use TO_CHAR like this:
to_char(number,'999999.99')
For example:
SQL> select to_char(1234.5678,'999999.99')||' DR' as display from dual;
DISPLAY
-------------
1234.57 DR
The presence of a debit implies the need for a credit. In Oracle SQL we can use the SIGN() function to tell whether a number is positive or negative...
SQL> select to_char(abs(amt), 'fm999g999d00')||' '
2 ||case when sign(amt) = -1 then 'DR' else 'CR' end as fmt_amt
3 from transactions
4 order by txn_ts, txn_id
5 /
FMT_AMT
--------------
200.00 CR
200.00 DR
788.67 CR
788.67 DR
SQL>
The answers here that suggested TO_CHAR are correct, but if you're calling this SQL from the application code:
Get the number without formatting it with the SQL and then use your programming language to format it. For example, in Java, use the DecimalFormat class. In other words, leave formatting for the application specific code, not for the SQL.
The additional characters can be specified as part of the conversion by enclosing them in double-quotes, which might make things a little more simple:
To_Char(amount,'fm999G999G990D00" DR"')
Related
This is the syntax I'm using when developing my SQL payload. I'm wondering why to_char is needed to perform the 1 divided by 0 operation. I read the to_char page but couldn't find an explanation. Thank you
SELECT CASE WHEN (1=2) THEN to_char(1/0) ELSE NULL END FROM dual
You cannot divide by zero. This causes an error. The problem is another.
In your example like '(1=2)' is always false Oracle does not execute the expression 'to_char(1/0)' and always returns null.
Why do you think that you need to_char? In example you posted, you certainly don't:
With to_char:
SQL> SELECT CASE WHEN (1=2) THEN to_char(1/0) ELSE NULL END result FROM dual;
R
-
Without it:
SQL> SELECT CASE WHEN (1=2) THEN 1/0 ELSE NULL END result FROM dual;
RESULT
----------
SQL>
What happens if you remove to_char? Maybe you didn't post code you really use, because it would help us help you. This is, as you were already told, meaningless because condition is never met so Oracle doesn't even execute division by zero (which you should then handle, somehow).
So, how exactly are you "developing your SQL payload"?
I want to check a date for correctness. (Let's not talk about the fact, that the date is stored in a varchar please ...)
Dates are stored like DDMMYYYY so for instance 24031950 is a correct date. 240319 is not.
So I do this, when the call works, it's a correct date:
select to_date('24031950','DDMMYYYY') from dual;
But unfortunately this also does not return an error:
select to_date('240319','DDMMYYYY') from dual (why?);
But it's interesting, that this one does not work:
select to_date('190324','YYYYMMDD') from dual;
So, how to enforce a check o 4 digit year with the given format mask?
Thanks!
Quoting the docs:
Oracle Database converts strings to dates with some flexibility. [...]
And I believe that flexibility is what you are seeing. You can turn it off with the fx modifier:
FX: Requires exact matching between the character data and the format model
select to_date('240319','fxDDMMYYYY') from dual;
Gives an ORA-01862 error.
Just an additional note to Mat's answer. fx acts like a switch in the string.
For example TO_DATE('2019-11-5','fxYYYY-MM-DD') gives an ORA-01862 error because exact matching applies for the entire string. If you need exact match only for parts of the string, then use for example
TO_DATE('2019-11-5','fxYYYY-MM-fxDD')
In this case YYYY-MM- has to match exactly, whereas DD applies flexible (or lazy) match.
To check whether it is in correct format without exceptions you can also use regex functions.
One possible way would to be check if the string contains 8 digits:
select REGEXP_INSTR ('24031950', '[0-9]{8}') from dual;
1
select REGEXP_INSTR ('240350', '[0-9]{8}') from dual;
0
I got a bug report where Oracle 10g was truncating return values from to_char(datetime):
SQL> select to_char(systimestamp, '"day:"DD"hello"') from dual;
TO_CHAR(SYSTIMESTAMP,'"DAY:"DD"HE
---------------------------------
day:27hel
Notably, this does not appear to happen in Oracle 11g. My question is, why does it happen at all? Is there some configuration variable to set to tell to_char(datetime) to allocate a bigger buffer for its return value?
I'm not sure but it might be just displaying in SQL*Plus. Have you tried to run it in Toad? Or if you assign result to varchar2 in PL/SQL block and output result?
Here what I've found in SQL*Plus Reference for 10g:
The default width and format of unformatted DATE columns in SQL*Plus
is determined by the database NLS_DATE_FORMAT parameter. Otherwise,
the default format width is A9. See the FORMAT clause of the COLUMN
command for more information on formatting DATE columns.
Your values is trimmed to 9 characters which corresponds to default A9 format. I don't have same version and this behaviour is not reproducing in 11g so can you please check my theory?
I've got the same problem and I know the solution.
I use Release 11.2.0.4.0 but I beleave it is possible to repeat the situation in other versions. It somehow depends on client. (E.g. I cannot repeat it using SQL*Plus, only with PL/SQL Devepoper)
Try this:
select to_char(systimestamp, '"day:"DD"йцукенг OR any other UTF-encoded-something"') from dual
union all
select to_char(systimestamp, '"day:"DD"hello"') from dual;
You'll get the following result:
day:08йцукенг OR any other UTF-encoded-so
day:08hello
You can see the "mething" is lost. This is exactly 7 bytes exceeded because of 7 two-byte simbols "йцукенг". Oracle allocates buffer for the number of characters, not a number of required bytes.
The command
alter session set nls_length_semantics=byte/char
unfortunately does not affect this behavior.
So my solution is to cast a result as varchar2(enough_capacity)
select cast(to_char(systimestamp, '"day:"DD"йцукенг OR any other UTF-encoded-something"') as varchar(1000)) from dual
union all
select to_char(systimestamp, '"day:"DD"hello"') from dual
Explicit typecasting makes expression independent from client or configuration.
BTW, the same thing happens in all implicit to_char-conversions. E.g.
case [numeric_expression]
when 1 then '[unicode_containing_string]'
end
Result might be cutted.
I have some issues with how sqlplus output is formatted for the terminal and I am just thinking of writing a script around sqlplus and fixing these.
On the other hand, wow that seems really lame. Because Oracle has several tons of tools written. Yet it seems difficult to get what I want. Does anyone have another suggestion?
First, I want smarter column widths. If I create a table with a column whose max size is 200 characters but then I put "abc", "xyz" and "123" in it, do I need a 200-space wide column on the terminal to display the contents? I do not think so. I think I need 3 characters plus a couple for padding. Yet Oracle insists on giving me a 200-character wide column. Unless there is somewhere to fix this.
Second, I want easy access to a sideways display of the columns, like using \G at the end of the command in MySQL. I know there is a way to do this in Oracle but it seemed complicated. Why could there not just be a simple switch? Like a \G at the end of the command? There can be if I wrap the output to sqlplus and do this myself.
So, the question seems to be this. Should I write a simple script around sqlplus to give me what I want, or is there a way to get Oracle to give me this behavior In sqlplus? And if there is, how much extra information will I have to stuff into my head to make this work? Because it does not seem as though it should be very complicated. But Oracle is certainly not making it easy.
First of all I suggest you look over the SQL*plus reference - you might find some useful tips there like adjusting a column width
COL column_name for a20
you can set up your own settings in the GLOGIN file. over time, like any other CMD, you'll get your preferences just right.
To describe a table you can use DESC. if you want more data write your own script and reuse it with #.
If all this doesn't work for you, you can always switch to a GUI like Toad or SQL developer.
EDIT:
I'm adding one of my own scripts to show you some tricks on how to make SQL*Plus more friendly on the command line. This one is for getting segment sizes.
/* This is the trick - clears &1 and &2 if received an empty string */
set ver off feed off
col 1 new_v 1
col 2 new_v 2
select 1,2 from dual where 1=0;
variable p_owner varchar2(30)
variable p_segment varchar2(30)
/* set bind variables */
begin
:p_owner := '&1';
:p_segment := '&2';
end;
/
set feed 1
break on segment_type skip 1
column MB for a25
select
segment_type,
decode(gi_segment_name + gi_segment_type + gi_tablespace_name , 3 ,'...Grand Total', segment_name) SEGMENT_NAME,
to_char(round(MB,3),'99,999,999.99') MB ,
nvl(tablespace_name,'-*-') tablespace_name
from (
select tablespace_name , segment_type , segment_name , sum(bytes/1024/1024) MB ,
grouping_id(segment_name) gi_segment_name ,
grouping_id(segment_type) gi_segment_type ,
grouping_id(segment_type) gi_tablespace_name
from dba_segments
where ((:p_owner is null and owner = user) or owner like upper(:p_owner))
and (:p_segment is null or segment_name like upper('%'||:p_segment||'%'))
group by rollup(tablespace_name, segment_type , segment_name)
)
where not (gi_segment_name = 1 and gi_segment_type = 0 and gi_tablespace_name = 0)
order by decode(segment_type,'TABLE','0','TABLE PARTITION','1','INDEX','2','INDEX PARTITION','3',segment_type) ,
(case when segment_name like '.%' then 'z' else 'a' end) ,
gi_segment_name ,
MB desc ,
segment_name;
clear break
/* clear definition for &1 and &2 after being used.
allows the variable to be null the next run. */
undefine 1
undefine 2
I'll walk you through some of the things iv'e done here
The script accepts two parameters. The first 4 lines clears the
parameter if none received. if you don't do this SQL*Plus will prompt
you for them. And we dont want that.
Setting the binds was more of a big deal in past version. It's
intended to save Hard / Soft parse. latest version solve this
problem. It's still a best practice though.
The break is a nice touch. You'll see it.
The grouping Id show me the sub totals on several levels.
I've added two parameter, owner and segment name. both can contain
wild card. both can be null. If non provided the query will fetch the
current user segments.
Order by decode enabled me to set a custom sort order for different
segment types. You can change it as you wish.
I'm executing the script like this
my segments :
#seg
Scott's segments
#seg scott
Scott's Emp related segments
#seg scott emp
I have similar scripts for session, longops, wait events, tables, constraints, locks, kill session etc .... during my daily routine i rarely write SQL for querying this stuff any more.
I'm trying to find an efficient, generic way to convert from string to a number in PL/SQL, where the local setting for NLS_NUMERIC_CHARACTERS settings is inpredictable -- and preferable I won't touch it. The input format is the programming standard "123.456789", but with an unknown number of digits on each side of the decimal point.
select to_number('123.456789') from dual;
-- only works if nls_numeric_characters is '.,'
select to_number('123.456789', '99999.9999999999') from dual;
-- only works if the number of digits in the format is large enough
-- but I don't want to guess...
to_number accepts a 3rd parameter but in that case you to specify a second parameter too, and there is no format spec for "default"...
select to_number('123.456789', null, 'nls_numeric_characters=''.,''') from dual;
-- returns null
select to_number('123.456789', '99999D9999999999', 'nls_numeric_characters=''.,''') from dual;
-- "works" with the same caveat as (2), so it's rather pointless...
There is another way using PL/SQL:
CREATE OR REPLACE
FUNCTION STRING2NUMBER (p_string varchar2) RETURN NUMBER
IS
v_decimal char;
BEGIN
SELECT substr(VALUE, 1, 1)
INTO v_decimal
FROM NLS_SESSION_PARAMETERS
WHERE PARAMETER = 'NLS_NUMERIC_CHARACTERS';
return to_number(replace(p_string, '.', v_decimal));
END;
/
select string2number('123.456789') from dual;
which does exactly what I want, but it doesn't seem efficient if you do it many, many times in a query. You cannot cache the value of v_decimal (fetch once and store in a package variable) because it doesn't know if you change your session value for NLS_NUMERIC_CHARACTERS, and then it would break, again.
Am I overlooking something? Or am I worrying too much, and Oracle does this a lot more efficient then I'd give it credit for?
The following should work:
SELECT to_number(:x,
translate(:x, '012345678-+', '999999999SS'),
'nls_numeric_characters=''.,''')
FROM dual;
It will build the correct second argument 999.999999 with the efficient translate so you don't have to know how many digits there are beforehand. It will work with all supported Oracle number format (up to 62 significant digits apparently in 10.2.0.3).
Interestingly, if you have a really big string the simple to_number(:x) will work whereas this method will fail.
Edit: support for negative numbers thanks to sOliver.
If you are doing a lot of work per session, an option may be to use
ALTER SESSION SET NLS_NUMERIC_CHARACTERS = '.,'
at the beginning of your task.
Of course, if lots of other code is executed in the same session, you may get funky results :-)
However we are able to use this method in our data load procedures, since we have dedicated programs with their own connection pools for loading the data.
Sorry, I noticed later that your question was for the other way round. Nevertheless it's noteworthy that for the opposite direction there is an easy solution:
A bit late, but today I noticed the special format masks 'TM9' and 'TME' which are described as "the text minimum number format model returns (in decimal output) the smallest number of characters possible." on https://docs.oracle.com/cloud/latest/db112/SQLRF/sql_elements004.htm#SQLRF00210.
It seems as if TM9 was invented just to solve this particular problem:
select to_char(1234.5678, 'TM9', 'NLS_NUMERIC_CHARACTERS=''.,''') from dual;
The result is '1234.5678' with no leading or trailing blanks, and a decimal POINT despite my environ containing NLS_LANG=GERMAN_GERMANY.WE8MSWIN1252, which would normally cause a decimal COMMA.
select to_number(replace(:X,'.',to_char(0,'fmd'))) from dual;
btw
select to_number(replace('1.2345e-6','.',to_char(0,'fmd'))) from dual;
and if you want more strict
select to_number(translate(:X,to_char(0,'fmd')||'.','.'||to_char(0,'fmd'))) from dual;
Is it realistic that the number of digits is unlimited?
If we assume it is then isn't it a good reason to look into the requirements more carefully?
If we have that fantastic situation when the initial string is super long, then the following does the trick:
select
to_number(
'11111111.2222'
, 'FM' || lpad('9', 32, '9') || 'D' || lpad('9', 30, '9')
, 'NLS_NUMERIC_CHARACTERS=''.,'''
)
from
dual