Insert white space in oracle APEX currency format mask - oracle

I'm using oracle APEX 20.1 and have a report with a column that displays currency values.
Since I'm from Europe I need the currency symbol to be behind the value (unlike the typical $amount format you see often in America).
I achieved this by changing the column's format mask to 'FM999G999G999G999G990D00L'.
This works well so far, but visually I would prefer if there was a whitespace between the end of the number (D00) and the currency symbol (L). Is there a way to insert a static whitespace in this format string?
I already looked through oracle's documentation on currency format strings, but they do not seem to mention such an option to include an always-there whitespace or an arbitrary static character.
Thank you in advance.

You can't include punctuation or character literals in a number mask as you can for dates, unfortunately.
You can include a space as part of the currency symbol itself - that is a string, not a character, and can be up to 10 bytes:
to_char(<number>, 'FM999G999G999G999G990D00L', 'nls_currency='' $''')
though that then uses a fixed currency symbol, not the session value from the L format element; you can get it dynamically from the session parameters:
to_char(
<number>,
'FM999G999G999G999G990D00L',
(
select 'nls_currency='' ' || value || ''''
from nls_session_parameters where parameter = 'NLS_CURRENCY'
)
)
which is a bit ugly. And you might not actually want the session's currency symbol; it might be more appropriate to always use the symbol that's relevant to that data.
And I imagine neither of those will fit in to Apex's numeric column formatting, so you would probably need to do that to_char() call explicitly in your query and have Apex just treat it as a pre-formatted string. (I have no idea how formatting works in Apex - from your description I'm assuming there is somewhere you define a format mask for a column in an interactive grid or whatever; but maybe you are already calling to_char().)
You can also change the currency symbol for the session:
alter session set nls_currency = ' €';
select to_char(123.45, 'FM999G999G999G999G990D00L') from dual;
123.45 €
which might be an option but would affect all currency fields - where the L format element is used - though maybe that's a good thing.
db<>fiddle.

Related

Special Character issue in Oracle DB

I need to update value in one table, which is having special character.
Below is the Update Query I have Executed:
UPDATE TABLE_X
SET DISPLAY_NAME = 'AC¦', NATIVE_IDENTITY='AC¦'
WHERE ID='idNumber'
Special Character "¦" is not getting updated in Oracle.
I have already tried below approaches:
Checked the character set being used in Oracle using below query
select * from nls_database_parameters where parameter='NLS_CHARACTERSET';
It is having "US7ASCII" Character set.
I have tried to see if any of the character set will help using below query
SELECT CONVERT('¦ ', 'ASCII') FROM DUAL;
I have tried below different encoding:
WE8MSWIN1252
AL32UTF8
BINARY - this one is giving error "ORA-01482: unsupported character set"
Before Changing the character set in DB i wanted to try out 'CONVERT' function from Oracle, but above mentioned character set is either returning "Block Symbol" or "QuestionMark � " Symbol.
Any idea how can I incorporate this special symbol in DB?
Assuming that the character in question is not part of the US7ASCII character set, which it does not appear to be unless you want to replace it with the ASCII vertical bar character |, you can't validly store the character in a VARCHAR2 column in the database.
You can change the database character set to a character set that supports all the characters you want to represent
You can change the data type of the column to NVARCHAR2 assuming your national character set is UTF-16 which it would normally be.
You can store a binary representation of the character in some character set you know in a RAW column and convert back from the binary representation in your application logic.
I would prefer changing the database character set but that is potentially a significant change.

Oracle a non-numeric character was found where a numeric was expected

I have problem with some thing input multiple date through prompt
my query something like
select something
from
something
where
to_date (bus.TDATE) not in (:didb1)
I want to input like '12-Jun-2016','11-Jun-2016'
i am doing php oracle,
My code following:
select bus.*,con.* from
BusinessPayment bus,
ConsumerPayment con
where bus.TDATE=con.TDATE
and to_date (bus.TDATE) not in (:didbv)
');
$bscode1='11-June-2016','10-June-2016','09-June-2016';
oci_bind_by_name($stid, ':didbv', $bscode1);
oci_execute($stid);
You can't use a single bind variable to represent a list of values in an in() clause. Bind variables don't contain multiple values; the value you bind is seen as a single string value. So you're effectively doing:
where
to_date (bus.TDATE) not in (q'['11-June-2016','10-June-2016','09-June-2016']')
If TDATE is already a date type - which it hopefully is, and the joins suggest it might be - then you should not be passing that through to_date() - you are doing an implicit conversion from date to string, then a semi-explicit conversion back to a date, both using your session's NLS_DATE_FORMAT. That is either doing unnecessary work, or losing resolution, depending on your format model and whether the dates have times. If the intention is to ignore the time part of the value then there are better ways to do that.
Anyway, since that is a date now whatever type it was before, the right had side of that filter will also be converted to a date, so you're doing:
where
to_date (bus.TDATE) not in (to_date(q'['11-June-2016','10-June-2016','09-June-2016']'))
... and it's that which is throwing the exception, whatever your NLS settings are. Even if you passed a single value it would error because of the embedded single quotes. You can replicate that with:
select to_date(q'['11-June-2016','10-June-2016','09-June-2016']') from dual;
which also gets ORA-01858: a non-numeric character was found where a numeric was expected.
Ideally you would pass the individual date strings as elements of an array, but you can also work around this with an XML hack. You can pass a single string containing comma-delimited values to XMLTable(), and it will split it in to rows:
select * from xmltable(q'['11-June-2016','10-June-2016','09-June-2016']');
COLUMN_VALUE
--------------------------------------------------------------------------------
11-June-2016
10-June-2016
09-June-2016
Then you can convert each of those values to a date:
select to_date(column_value, 'DD-Month-YYYY')
from xmltable(q'['11-June-2016','10-June-2016','09-June-2016']')
and use that in a subquery or a join:
select * from dual
where trunc(sysdate) not in (select to_date(column_value, 'DD-Month-YYYY')
from xmltable(q'['11-June-2016','10-June-2016','09-June-2016']'));
And that works with a string bind variable, so your code would be:
select bus.*,con.*
from BusinessPayment bus
join ConsumerPayment con
on bus.TDATE=con.TDATE
where bus.TDATE not in (select to_date(column_value, 'DD-Month-YYYY')
from xmltable(:didbv));
I've modified this to use ANSI join syntax, which isn't relevant but there's rarely a reason to use the ancient syntax you have. If TDATE does include the time you'll need to modify it a bit - truncating is simplest but might affect performance.
Or you could join:
select bus.*,con.*
from xmltable(:didbv) x
join BusinessPayment bus
on bus.TDATE >= to_date(x.column_value, 'DD-Month-YYYY')
and bus.TDATE < to_date(x.column_value, 'DD-Month-YYYY') + 1
join ConsumerPayment con
on bus.TDATE=con.TDATE
In this version TDATE can have a time, and it matches any time on the days specified in the bind variable.
It would be better to supply the dates in a format that doesn't have the month name in it, as that could give you problems when run in different sessions or locales. If you know the PHP side will always be English you could force that to be recognised:
on bus.TDATE >= to_date(x.column_value, 'DD-Month-YYYY', #NLS_DATE_LANGUAGE=ENGLISH')
but if you can change the PHP format to use month numbers, and change the Oracle format model to match, that would be a bit simpler.

Date format not recognized while returning results

select * from table where trunc(value1)=to_date('25-AUG-15','DD-MON-YY');
This is fine
select * from table where trunc(value1)=to_date('25-AUG-15','DD-Mon-YY');
This returned as well although the valid value should be 25-Aug-15
Even this works,
select * from table where trunc(value1)=to_date('25/AUG/15','DD-MON-YY');
result is returned
And this,
select * from table where trunc(value1) = to_date('25-AUG-15', 'DD-MM-YY');
result is returned
but this works very well
select * from table where trunc(value1) = to_date('25-AUG-15','MMDDYY');
it checks for the month, which is not found and returns error(well parsed!!!)
Why is that format specifier is not performing strict check on the date value supplied?
Thanks.
This seems to be Oracle trying to do you a solid and make it easy to parse dates into something sensible. I can't find any documentation to support this, but not only is the format mask case insensitive, but it would appear that any sequence of non-alphanumeric characters that are not a control characters that appear in either the input string or the format mask are treated as required wildcards, such that from Oracle's perspective:
TO_DATE('17!!!SEP£££15', 'DD$$$MON***YY')
is identical to:
TO_DATE('170915', 'DDMONYY')
If the number and position of the wildcards in your input don't match those of the format mask, you'll get a exception relating to the next token it is looking for:
TO_DATE('17!!!!SEP-15', 'DD-MON-YY')
ORA-01843: not a valid month
However, it gets even more weird when you look at how the wildcards in the format mask are interpreted. It seems that between tokens, any sequence of non-alphanumeric characters is treated as a single but optional wildcard, such that:
TO_DATE('17-SEP-15','DD----------------MON-YY')
is the same as:
TO_DATE('17-SEP-15','DD-MON-YY')
and because the wildcards in the format mask are option, also has the same effect as:
TO_DATE('17-SEP-15','DD-MON-YY')

Restrict thousand separator in TO_NUMBER (Oracle)

I'm trying to parse numbers using the following code
TO_NUMBER('1,234.56', '9999999D99')
For some reason comma is ignored and the value is parsed correctly, despite the format doesn't have it. Is there any way to restrict usage of thousand group separator?
So far I only came up with setting a bogus symbol as a separator with the hope that user will not use it
TO_NUMBER('1,234.56', '9999999D99', 'NLS_NUMERIC_CHARACTERS=''.ã''');
This is a very strange request - if Oracle is correctly converting the string to a number then it seems to be doing it's job correctly. However, if you really need to do this for whatever reason then simply remove the format mask.
SQL> select to_number('1,234.56') from dual;
select to_number('1,234.56') from dual
*
ERROR at line 1:
ORA-01722: invalid number
SQL> select to_number('1234.56') from dual;
TO_NUMBER('1234.56')
--------------------
1234.56
SQL>
Though the SQL Language Reference doesn't mention any default values I believe that the default value for the format mask described in the OLAP DML Reference for TO_NUMBER() applies:
The default number format identifies a period (.) as the decimal marker and does not recognize any other symbol.
This, in turn, means that a comma is an invalid value for the conversion and thus the conversion will fail.

Different matches when using prepared statements on CHAR(3) column

I had to make a CHAR(1 CHAR) column wider and I forgot to change the column type to VARCHAR2:
DUPLICADO CHAR(3 CHAR)
I noticed the error when my PHP app would no longer find exact matches, e.g.:
SELECT *
FROM NUMEROS
WHERE DUPLICADO = :foo
... with :foo being #4 didn't find the 3-char padded #4 value. However, I initially hit a red herring while debugging the query in SQL Developer because injecting raw values into the query would find matches!
SELECT *
FROM NUMEROS
WHERE DUPLICADO = '#4'
Why do I get matches with the second query? Why do prepared statements make a difference?
To expand a little on my comments, I found a bit in the documentation that explains difference between blankpadded and nonpadded comparison:
http://docs.oracle.com/database/121/SQLRF/sql_elements002.htm#BABJBDGB
If both values in your comparison (the two sides of the equal sign) have datatype CHAR or NCHAR or are literal strings, then Oracle chooses blankpadded comparison. That means that if the lengths are different, then it pads the short one with blanks until they are the same length.
With the column DUPLICADO being a CHAR(3), the value '#4' is stored in the column as three characters '#4 ' (note the blank as third character.) When you do DUPLICADO = '#4' the rule states Oracle will use blankpadded comparison and therefore blankpad the literal '#4' until it has the same length as the column. So it actually becomes DUPLICADO = '#4 '.
But when you do DUPLICADO = :foo, it will depend on the datatype of the bind variable. If the datatype is CHAR, it will also perform blankpadded comparison. But if the datatype is VARCHAR2, then Oracle will use non-padded comparison and then it will be up to you to ensure to do blankpadding where necessary.
Depending on client or client language you may be able to specify the datatype of the bind variable and thereby get blankpadded or nonpadded comparison as needed.
SQL Developer may be a special case that might not allow you to specify datatype - it just possibly might default to bind variables always being datatype VARCHAR2. I don't know sufficient about SQL Developer to be certain about that ;-)

Resources