Why does this query return a money value? - sql

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.

Related

CASTING to NUMERIC in SQL

I am trying to understand the ARPU calculation in SQL from the following code, however I don't understand why the author has used NUMERIC with revenue in the 2nd query? Won't revenue (meal_price * order quantity) be numeric anyway?
The issue is probably the following. NUMERIC is a specific data type. However, it is not clear that meal_price and order_quantity are specifically NUMERIC -- and not some other type such as INT.
Many databases do integer division for INT, so 1 / 2 is 0 rather than 0.5.
The conversion to NUMERIC is a simple way to avoid integer division.
Of course if a and b are numeric types , a * b will be numeric type
But there are many different numeric types, see
https://www.postgresql.org/docs/13/datatype-numeric.html
NUMERIC is a KEYWORK to specify numeric type of arbitrary précision, see previous link, it's often used to do exact calculations (accouinting) that cannoy be done in foating type.
In your case the author choosed to define the type he wants to use and not let the system/db choose for him. (try to figure out if a and b are integer what shoult be the type of the result 2 * 4 / 3 ?). It's a good practice.

How to multiply string value to longint in SQL

I have the below data which I want to multiply together, column A times column B to get column C.
A has datatype string and B has datatype long.
A B
16% 894
15% 200
I have tried this expression in query cast(A as int)*B but it is giving me an error.
You can try below way -
select cast(left(A, patindex('%[^0-9]%', A+'.') - 1) as int)*B
from tablename
You need to remove the '%' symbol before attempting your cast. And assuming you are actually wanting to calculate the percentage, then you also need to divide by 100.00.
cast(replace(A,'%','') as int)/100.00*B
Note: You need to use 100.00 rather than 100 to force decimal arithmetic instead of integer. Or you could cast as decimal(9,2) instead of int - either way ensures you get an accurate result.
You may well want to reduce the number of decimal points returned, in which case cast it back to your desired datatype e.g.
cast(cast(replace(A,'%','') as int)/100.00*# as decimal(9,2))
Note: decimal(9,2) is just an example - you would use whatever precision and scale you need.
The syntax of the cast in SQL Server is CAST(expression AS TYPE);
As you cannot convert '%' to an integer so you have to replace that with an empty character
as below:
SELECT cast(replace(A,'%','') AS int);
Finally you can write as below:
SELECT (cast(replace(A,'%','') AS int)/100.00)*B as C;

Convert number to decimal in pentaho

In pentaho,i am facing convertion problem when insert the data from selected values. I need to be able to pick up whatever is in that field "as is" and not change it at all.
example
Field - 0.13
inserted field -0
0.13 is converted to 0 but it should be 0.13 only. where as 110 is converted to 110 correctly. Issue with the decimal values, all decimal values converted to 0.
Thanks
There are a few things you can check on the Select Values.
Decimal Field - This checks which is the sign for decimal value for this number, it uses your system Decimal value, so if you are using English Windows/Unix, the default decimal is the dot, where as in other regions it might be the comma.
Always check which, dot or comma, you are receiving for the number before converting.
One quick note as well, Steps AFTER a Group By will receive ANY number with the mask #.#, which is only 1 decimal number after the sign. The data is not lost, it's simply shown with a different mask, be sure to also put that in the select values as well.
The Select Values should look like this for a Number like 0.13 to show as such
EDIT:
Note that in Precision and Format i have used the same number of zeros after the decimal sign, this will account for a maximum of 5 decimal cases after the sign, as a mask, if you have values with more than 5 decimal cases it will load as such, just not show.
In "foreign" Countries ( with e.g. SQLite ) these two steps might help:
1st: in the select statement of "Table input" replace the field (e.g. TRANSAMOUNT ) with field*1.0 field (e.g. TRANSAMOUNT *1.0 TRANSAMOUNT ), so every value will be casted implicitly and
2nd: in the Meta-data Tab ( as mentioned below ) change the Type to Number and choose the appropriate "Date Locate" ( e.g. de_DE ) which also affects Numbers ..

How to remove currency symbol from price column?

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

How do I count decimal places in SQL?

I have a column X which is full of floats with decimals places ranging from 0 (no decimals) to 6 (maximum). I can count on the fact that there are no floats with greater than 6 decimal places. Given that, how do I make a new column such that it tells me how many digits come after the decimal?
I have seen some threads suggesting that I use CAST to convert the float to a string, then parse the string to count the length of the string that comes after the decimal. Is this the best way to go?
You can use something like this:
declare #v sql_variant
set #v=0.1242311
select SQL_VARIANT_PROPERTY(#v, 'Scale') as Scale
This will return 7.
I tried to make the above query work with a float column but couldn't get it working as expected. It only works with a sql_variant column as you can see here: http://sqlfiddle.com/#!6/5c62c/2
So, I proceeded to find another way and building upon this answer, I got this:
SELECT value,
LEN(
CAST(
CAST(
REVERSE(
CONVERT(VARCHAR(50), value, 128)
) AS float
) AS bigint
)
) as Decimals
FROM Numbers
Here's a SQL Fiddle to test this out: http://sqlfiddle.com/#!6/23d4f/29
To account for that little quirk, here's a modified version that will handle the case when the float value has no decimal part:
SELECT value,
Decimals = CASE Charindex('.', value)
WHEN 0 THEN 0
ELSE
Len (
Cast(
Cast(
Reverse(CONVERT(VARCHAR(50), value, 128)) AS FLOAT
) AS BIGINT
)
)
END
FROM numbers
Here's the accompanying SQL Fiddle: http://sqlfiddle.com/#!6/10d54/11
This thread is also using CAST, but I found the answer interesting:
http://www.sqlservercentral.com/Forums/Topic314390-8-1.aspx
DECLARE #Places INT
SELECT TOP 1000000 #Places = FLOOR(LOG10(REVERSE(ABS(SomeNumber)+1)))+1
FROM dbo.BigTest
and in ORACLE:
SELECT FLOOR(LOG(10,REVERSE(CAST(ABS(.56544)+1 as varchar(50))))) + 1 from DUAL
A float is just representing a real number. There is no meaning to the number of decimal places of a real number. In particular the real number 3 can have six decimal places, 3.000000, it's just that all the decimal places are zero.
You may have a display conversion which is not showing the right most zero values in the decimal.
Note also that the reason there is a maximum of 6 decimal places is that the seventh is imprecise, so the display conversion will not commit to a seventh decimal place value.
Also note that floats are stored in binary, and they actually have binary places to the right of a binary point. The decimal display is an approximation of the binary rational in the float storage which is in turn an approximation of a real number.
So the point is, there really is no sense of how many decimal places a float value has. If you do the conversion to a string (say using the CAST) you could count the decimal places. That really would be the best approach for what you are trying to do.
I answered this before, but I can tell from the comments that it's a little unclear. Over time I found a better way to express this.
Consider pi as
(a) 3.141592653590
This shows pi as 11 decimal places. However this was rounded to 12 decimal places, as pi, to 14 digits is
(b) 3.1415926535897932
A computer or database stores values in binary. For a single precision float, pi would be stored as
(c) 3.141592739105224609375
This is actually rounded up to the closest value that a single precision can store, just as we rounded in (a). The next lowest number a single precision can store is
(d) 3.141592502593994140625
So, when you are trying to count the number of decimal places, you are trying to find how many decimal places, after which all remaining decimals would be zero. However, since the number may need to be rounded to store it, it does not represent the correct value.
Numbers also introduce rounding error as mathematical operations are done, including converting from decimal to binary when inputting the number, and converting from binary to decimal when displaying the value.
You cannot reliably find the number of decimal places a number in a database has, because it is approximated to round it to store in a limited amount of storage. The difference between the real value, or even the exact binary value in the database will be rounded to represent it in decimal. There could always be more decimal digits which are missing from rounding, so you don't know when the zeros would have no more non-zero digits following it.
Solution for Oracle but you got the idea. trunc() removes decimal part in Oracle.
select *
from your_table
where (your_field*1000000 - trunc(your_field*1000000)) <> 0;
The idea of the query: Will there be any decimals left after you multiply by 1 000 000.
Another way I found is
SELECT 1.110000 , LEN(PARSENAME(Cast(1.110000 as float),1)) AS Count_AFTER_DECIMAL
I've noticed that Kshitij Manvelikar's answer has a bug. If there are no decimal places, instead of returning 0, it returns the total number of characters in the number.
So improving upon it:
Case When (SomeNumber = Cast(SomeNumber As Integer)) Then 0 Else LEN(PARSENAME(Cast(SomeNumber as float),1)) End
Here's another Oracle example. As I always warn non-Oracle users before they start screaming at me and downvoting etc... the SUBSTRING and INSTRING are ANSI SQL standard functions and can be used in any SQL. The Dual table can be replaced with any other table or created. Here's the link to SQL SERVER blog whre i copied dual table code from: http://blog.sqlauthority.com/2010/07/20/sql-server-select-from-dual-dual-equivalent/
CREATE TABLE DUAL
(
DUMMY VARCHAR(1)
)
GO
INSERT INTO DUAL (DUMMY)
VALUES ('X')
GO
The length after dot or decimal place is returned by this query.
The str can be converted to_number(str) if required. You can also get the length of the string before dot-decimal place - change code to LENGTH(SUBSTR(str, 1, dot_pos))-1 and remove +1 in INSTR part:
SELECT str, LENGTH(SUBSTR(str, dot_pos)) str_length_after_dot FROM
(
SELECT '000.000789' as str
, INSTR('000.000789', '.')+1 dot_pos
FROM dual
)
/
SQL>
STR STR_LENGTH_AFTER_DOT
----------------------------------
000.000789 6
You already have answers and examples about casting etc...
This question asks of regular SQL, but I needed a solution for SQLite. SQLite has neither a log10 function, nor a reverse string function builtin, so most of the answers here don't work. My solution is similar to Art's answer, and as a matter of fact, similar to what phan describes in the question body. It works by converting the floating point value (in SQLite, a "REAL" value) to text, and then counting the caracters after a decimal point.
For a column named "Column" from a table named "Table", the following query will produce a the count of each row's decimal places:
select
length(
substr(
cast(Column as text),
instr(cast(Column as text), '.')+1
)
) as "Column-precision" from "Table";
The code will cast the column as text, then get the index of a period (.) in the text, and fetch the substring from that point on to the end of the text. Then, it calculates the length of the result.
Remember to limit 100 if you don't want it to run for the entire table!
It's not a perfect solution; for example, it considers "10.0" as having 1 decimal place, even if it's only a 0. However, this is actually what I needed, so it wasn't a concern to me.
Hopefully this is useful to someone :)
Probably doesn't work well for floats, but I used this approach as a quick and dirty way to find number of significant decimal places in a decimal type in SQL Server. Last parameter of round function if not 0 indicates to truncate rather than round.
CASE
WHEN col = round(col, 1, 1) THEN 1
WHEN col = round(col, 2, 1) THEN 2
WHEN col = round(col, 3, 1) THEN 3
...
ELSE null END