How to remove currency symbol from price column? - sql

I have a price column which is string and has price for the product from all over the world , now When I try to perform any operation like sum I am getting error.
So my question is how can I remove currency symbol from price column for all the countries?
Here is my sample input:-
locale price
cs_CZ 2462475,38 K
da_DK kr 591.872,50
de_AT 267,70
de_CH CHF 1'998.99
de_DE 1.798,09
en_AE AED7,236.20
en_AU $1,699.00
en_BD Tk999,999.00
en_HK HK$6,188.00
en_HU Ft344,524,655.48
tr_TR 2.344.697,66 TL

Postgres offloads most locale handling to the operating system. So the Postgres currency conversion routines will only work for you if the OS understands the locale names, and your price strings match its expected format.
For example, Windows won't accept da_DK as a locale, and even if it did, it will not accept the string kr 591.872,50, as it expects the Danish currency symbol to be kr. instead of kr.
That said, I think this should work reasonably well on a Linux-based server:
CREATE FUNCTION convert_currency(amount TEXT, locale TEXT) RETURNS NUMERIC AS
$$
BEGIN
PERFORM set_config('lc_monetary', locale || '.UTF-8', True);
RETURN amount::MONEY::NUMERIC;
END
$$
LANGUAGE plpgsql
SET lc_monetary TO DEFAULT;

You seem to have both decimal point and decimal comma but always two decimals (hopefully in the rest of the data too).
You can start by putting those values in a value list for testing (adding extra single quotes where needed).
Then you have to trim out spaces and letters with regular expressions. In the inner SELECT you get the substring with single quotes and commas for thousand separators still in it.
In the outer SELECT you replace the decimal commas in the decimal side and strip out thousand separators on the integer side. The result is cast to type numeric with which you can count sums etc.
SELECT (
regexp_replace(left(substring, length(substring) -3),'[.,'']','','g')
|| replace(right(substring, 3),',','.'))::numeric,
*
FROM (
SELECT substring(column1 from '(([0-9]+[,.''])*[0-9]+[.,][0-9]{2})[^0-9]*$'),
column1
FROM (
VALUES ('2462475,38 K'),
('kr 591.872,50'),
('267,70'),
('CHF 1''998.99'),
('1.798,09'),
('AED7,236.20'),
('$1,699.00'),
('Tk999,999.00'),
('HK$6,188.00'),
('Ft344,524,655.48'),
('2.344.697,66 TL')
) currencies
) sq1;
The following is the whole answer compatible with 9.0 version of PostgreSQL (no left() or right() functions used). Also values list is replaced with a SELECT query that you can replace with your own table and column. Finally it's all been enclosed in a SELECT query that demonstrates the use of the sum-function.
SELECT sum(numeric) FROM (
SELECT (
regexp_replace(substr(substring, 0, length(substring) -3),'[.,'']','','g')
|| replace(substr(substring, length(substring) -3, length(substring)),',','.'))::numeric,
*
FROM (
SELECT substring(column1 from '(([0-9]+[,.''])*[0-9]+[.,][0-9]{2})[^0-9]*$'),
column1
FROM (
SELECT column1 FROM your_table
) currencies
) sq1
) sq2

Related

Why does this query return a money value?

Today I wrote a query that should return an error. Instead, it returns the value 15 with column name why and data type money.
Do you have an idea why?
select \15why
Result:
why
15.00
You're specifying a constant:
money constants are represented as string of numbers with an optional decimal point and an optional currency symbol as a prefix
So select €15 results in a money constant, and so does select $15, as well as select ¥15.
There's a peculiarity as pointed out by Jeroen in the comments:
Because the yen sign (¥) is a currency indicator, and in some native Japanese character sets, its code point is the same as the one for backslash in ASCII.
See also MSDN: money and smallmoney (Transact-SQL).
So select \15 appears to be equal to select ¥15.
As for the column name: select 5a results in a column with the alias a and a value of 5. Because "a" is not a numeric suffix, it is treated as select 5 as a, where "as" is optional. Instead select 5e would return 5 in an unnamed column, because "e" is a numeric suffix.
So you've discovered a different way to write select ¥15 as why.

in db2 I am exporting the data price value getting like this "+00000000000000000000000020.96000" price value we have decimal column

In db2 when I exporting the data price value, I am getting like this
"+00000000000000000000000020.96000"
how to remove the before zeros of price value.
I am excepting like this "20.96000".
My Query like this
sum(orders.TOTALPRODUCT) this value I am getting like this "+00000000000000000000000020.96000"
db2 "EXPORT TO customerpurchase2016.csv OF del modified BY coldel,
SELECT userreg.logonid,
nvl(address.firstname,'')
||' '
|| address.lastname,
sum(orders.totalproduct) AS totalproduct,
sum(orders.totalproduct+orders.totaltax+orders.totalshipping+orders.totaladjustment) AS totalamount,
userdemo.field7
FROM orders,
userreg,
userdemo,
address
WHERE address.member_id=userdemo.users_id
AND userdemo.users_id=userreg.users_id
AND userreg.users_id=orders.member_id
AND orders.status NOT IN('J',
'P',
'X')
AND orders.lastupdate BETWEEN '2016-01-01-00.00.00.000000' AND '2016-12-30-12.00.00.000000'
AND address.status='P'
AND address.selfaddress=1
GROUP BY userreg.logonid,
userdemo.field7,
address.firstname,
address.lastname"
I can not test, but try using cast( sum(orders.TOTALPRODUCT) as decimal( 31, 6 ) in place of the sum(orders.TOTALPRODUCT) from the OP. And if leading zeroes persist, then likely the db2 being used is LUW [no mention of platform nor version info was made in the OP nor tags] and an issue may exist for [both explicit CHAR and possibly also the] implicit casting from numeric to character, whereby leading zeroes are known to be the result of a past defect; i.e. an older database may need modification to enable the casting to function without the leading zeroes per Notes in DB2 for Linux UNIX and Windows 10.1.0->Database fundamentals->SQL->Built-in functions->Scalar functions->CHAR
Decimal to character and leading zeros: In versions previous to version 9.7, the result for decimal input to this function includes leading zeros and a trailing decimal character. The database configuration parameter dec_to_char_fmt can be set to "V95" to have this function return the version 9.5 result for decimal input. The default value of dec_to_char_fmt for new databases is "NEW", which has this function return results which match the SQL standard casting rules and is consistent with results from the VARCHAR function.
you can use VARCHAR or TRIM OR STRIP functions when exporting table as below;
db2 "EXPORT TO customerpurchase2016.csv OF del modified BY coldel,
SELECT userreg.logonid,
nvl(address.firstname,'')
||' '
|| address.lastname,
TRIM(sum(orders.totalproduct)) AS totalproduct,
sum(orders.totalproduct+orders.totaltax+orders.totalshipping+orders.totaladjustment) AS totalamount,
userdemo.field7
FROM orders,
userreg,
userdemo,
address
WHERE address.member_id=userdemo.users_id
AND userdemo.users_id=userreg.users_id
AND userreg.users_id=orders.member_id
AND orders.status NOT IN('J',
'P',
'X')
AND orders.lastupdate BETWEEN '2016-01-01-00.00.00.000000' AND '2016-12-30-12.00.00.000000'
AND address.status='P'
AND address.selfaddress=1
GROUP BY userreg.logonid,
userdemo.field7,
address.firstname,
address.lastname"
Example;
A sample table:
create table pricetable (price decimal(31,5));
insert into pricetable (price) values(20.96);
insert into pricetable (price) values(21.97);
insert into pricetable (price) values(22.98);
insert into pricetable (price) values(20.99);
Exporting without functions;
CALL SYSPROC.ADMIN_CMD( 'EXPORT TO "/tmp/export" OF DEL MESSAGES ON SERVER SELECT PRICE FROM PRICETABLE' );
user#host:/tmp:>cat export
+00000000000000000000000020.96000
+00000000000000000000000021.97000
+00000000000000000000000022.98000
+00000000000000000000000020.99000
Exporting using varchar or trim or strip functions;
CALL SYSPROC.ADMIN_CMD( 'EXPORT TO "/tmp/export" OF DEL MESSAGES ON SERVER SELECT VARCHAR(PRICE) FROM PRICETABLE' );
user#host:/tmp:>cat export
"20.96000"
"21.97000"
"22.98000"
"20.99000"
you can tell the export-script to remove leading zeros in all columns be simply passing striplzeros as argument.
db2 "EXPORT TO customerpurchase2016.csv OF del modified BY coldel, striplzeros
SELECT userreg.logonid,
nvl(address.firstname,'')
...
See also https://www.ibm.com/support/knowledgecenter/de/SSEPGG_10.5.0/com.ibm.db2.luw.admin.cmd.doc/doc/r0008303.html#r0008303__d73620e525 for more options

AS400 thousand delimiter on numeric field

Is there a way to get a number formatted with a comma for thousand in numbers?
According to IBM documentation, this is the syntax:
DECIMAL(:newsalary, 9, 2, ',')
newsalary is the string (field)
9 is the precision
2 is the scale
, is the delimiter.
I tried:
SELECT DECIMAL ( T1.FIELD1 , 15 , 2 , "," ) AS TOTAL FROM TABLE T1
When trying it, I am getting the following error:
Message: [SQL0171] Argument 4 of function DECIMAL not valid.
DECIMAL converts from string type to a numeric type.
Numeric types don't have separators; only character representations of numbers have separators.
What tool are you using STRSQL, Run SQL Scripts or something else? Once you convert the string to a number, the tool should add the language appropriate separators when it displays the numeric data. For example, in STRSQL:
select decimal('12345.67', 12,2) as mynum
from sysibm.sysdummy1
Returns:
MYNUM
12,345.67
Using SQL to format strings is usually a bad idea. That should be left to whatever is consuming the data.
But if you really, really, really want to do it. You should create a user defined function (UDF) that does it for you. Here's an article, Make SQL Edit the Way You Want It To that includes source for for an EDITDEC function written in ILE RPG along with the SQL function definition you need to use it in an SQL statement.

How to check if a value is a number in SQLite

I have a column that contains numbers and other string values (like "?", "???", etc.)
Is it possible to add an "is number" condition to the where clause in SQLite? Something like:
select * from mytable where isnumber(mycolumn)
From the documentation,
The typeof(X) function returns a string that indicates the datatype of the expression X: "null", "integer", "real", "text", or "blob".
You can use where typeof(mycolumn) = "integer"
You could try something like this also:
select * from mytable where printf("%d", field1) = field1;
In case your column is text and contains numeric and string, this might be somewhat helpful in extracting integer data.
Example:
CREATE TABLE mytable (field1 text);
insert into mytable values (1);
insert into mytable values ('a');
select * from mytable where printf("%d", field1) = field1;
field1
----------
1
SELECT *
FROM mytable
WHERE columnNumeric GLOB '*[0-9]*'
select * from mytable where abs(mycolumn) <> 0.0 or mycolumn = '0'
http://sqlfiddle.com/#!5/f1081/2
Based on this answer
To test whether the column contains exclusively an integer with no other alphanumeric characters, use:
NOT myColumn GLOB '*[^0-9]*' AND myColumn LIKE '_%'
I.e., we test whether the column contains anything else than a digit and invert the result. Additionally we test whether it contains at least one character.
Note that GLOB '*[0-9]*' will find digits nested between other characters as well. The function typeof() will return 'text' for a column typed as TEXT, even if the text represents a number. As #rayzinnz mentioned, the abs() function is not reliable as well.
As SQLite and MySQL follow the same syntax and loose datatypes.
The query below is also possible
SELECT
<data>
, (
LENGTH(CAST(<data> AS UNSIGNED))
)
=
CASE WHEN CAST(<data> AS UNSIGNED) = 0
THEN CAST(<data> AS UNSIGNED)
ELSE (LENGTH(<data>)
) END AS is_int;
Note the <data> is BNF you would have the replace those values.
This answer is based on mine other answer
Running SQLite demo
For integer strings, test whether the roundtrip CAST matches the original string:
SELECT * FROM mytable WHERE cast(cast(mycolumn AS INTEGER) AS TEXT) = mycolumn
For consistently-formatted real strings (for example, currency):
SELECT * FROM mytable WHERE printf("%.2f", cast(mycolumn AS REAL)) = mycolumn
Input values:
Can't have leading zeroes
Must format negatives as -number rather than (number).
You can use the result of the function CAST( field as INTEGER) for numbers greater than zero and the simple condition like '0' per numbers equal to zero
SELECT *
FROM tableName
WHERE CAST(fieldName AS INTEGER) > 0
UNION
SELECT *
FROM tableName
WHERE fieldName like '0';
This answer is comprehensive and eliminates the shortcomings of all other answers. The only caveat is that it isn't sql standard... but neither is SQLite. If you manage to break this code please comment below, and I will patch it.
Figured this out accidentally. You can check for equality with the CAST value.
CASE {TEXT_field}
WHEN CAST({TEXT_field} AS INTEGER) THEN 'Integer' -- 'Number'
WHEN CAST({TEXT_field} AS REAL) THEN 'Real' -- 'Number'
ELSE 'Character'
END
OR
CASE
WHEN {TEXT_field} = CAST({TEXT_field} AS INTEGER) THEN 'Integer' --'Number'
WHEN {TEXT_field} = CAST({TEXT_field} AS Real) THEN 'Real' --'Number'
ELSE 'Character'
END
(It's the same thing just different syntax.)
Note the order of execution. REAL must come after INTEGER.
Perhaps their is some implicit casting of values prior to checking for equality so that the right-side is re-CAST to TEXT before comparison to left-side.
Updated for comment: #SimonWillison
I have added a check for 'Real' values
'1 frog' evaluated to 'Character' for me; which is correct
'0' evaluated to 'Integer' for me; which is correct
I am using SQLite version 3.31.1 with python sqlite3 version 2.6.0. The python element should not affect how a query executes.

How to use function in subquery

I have one table named MemberCheque where the fields are:
MemberName, Amount
I want to to show the name and the respective amount in numbers and as well as in words after separating the integer amount from the decimal. So my query is like:
SELECT MemName, Amount, (SELECT (Amount)%1*100 AS lefAmn, dbo.fnNumberToWords(lefAmn)+
'Hundred ', (Amount) - (Amount)%1 AS righAmnt, dbo.fnNumberToWords (righAmnt)+' Cents'
from MemberCheque) AS AmountInWords FROM MemberCheque
but my store procedure can take only integer value to change into words. So, I am doing separating the Amount into two parts before and after decimal but when I am trying to run this query it gives me error that lefAmn and righAmnt is not recognised. Because I am trying to send the parameter from the same query.
The first problem is that you have a subquery that is returning more than one value, and that is not allowed for a subquery in the select clause.
That answer to your specific question is to use cast() (or convert()) to make the numbers integers:
select leftAmt, rightAmt,
(dbo.fnNumberToWords(cast(leftAmt as int))+'Hundred ' +
dbo.fnNumberToWords(cast(rightAmt as int))+' Cents'
) as AmountInWords
from (SELECT (Amount%1)*100 AS leftAmt,
(Amount) - (Amount)%1 AS rightAmt
from MemberCheque
) mc
If you can't alter your function, then CAST the left/right values as INT:
CAST((Amount)%1*100 AS INT) AS lefAmn
CAST((Amount) - (Amount)%1 AS INT) AS righAmnt
You can't pass the alias created in the same statement as your function parameter, you need:
dbo.fnNumberToWords (CAST((Amount)%1*100 AS INT))
dbo.fnNumberToWords (CAST((Amount) - (Amount)%1 AS INT))