SSIS / SQL Server - dealing with various money type notations - sql

In a SQL Server money column how can I deal with different currency notations coming in from country specific Excel files via SSIS (in varchar - transformed to money), taking care of comma and dot representation to make sure the values stay correct?
For example if these are three column values in Excel:
22,333.44
22.333,44
22333,44
the first notation above will result in 22,3334, which of course is incorrect.
What do I need to do with the data? Is it a string replace or something more elegant?
thank you.

UPDATED:
After discussion in comments the problem has been clarified. The values in the excel column can be of many different regional formats (English using commas to separate thousands and '.' for decimal point, German using '.' for separating thousands and comma for decimal point).
Assuming that the destination format is English and you don't have an accompanying column to indicate the format then you're gonna have to implement a kludge of a workaround. If you can guarantee there will always be 2 numbers after the "decimal place" (comma in german format) then REPLACE(REPLACE(#Value,',',''),'.','') will get rid of every comma/point. Then you will have to get the length of the resulting varchar and manually insert a decimal (or comma) before the last 2 characters. Here's a sample implementation:
declare #number varchar(12),#trimmednumber varchar(12),#inserteddecimal varchar(12)
set #number='22.333,44'
select #trimmednumber=REPLACE(REPLACE(#number,',',''),'.','')
select #inserteddecimal=(LEFT(#trimmednumber,len(#trimmednumber)-2) + '.' + RIGHT(#trimmednumber,2))
select #number AS [Original],#trimmednumber AS [Trimmed],#inserteddecimal AS [Result]
And the results:
Original Trimmed Result
------------ ------------ ------------
22.333,44 2233344 22333.44
Original Answer:
I may be misunderstanding your question but if you take in those values as VARCHAR and insert them into MONEY columns then the implicit conversion should be correct.
Here's what I've knocked together to test:
declare #money_varchar1 varchar(12),#money_varchar2 varchar(12),#money_varchar3 varchar(12)
set #money_varchar1='22,333.44'
set #money_varchar2='22.333,44'
set #money_varchar3='22333,22'
declare #table table (Value money)
insert into #table values (#money_varchar1)
insert into #table values (#money_varchar2)
insert into #table values (#money_varchar3)
select * from #table
And the results:
Value
---------------------
22333.44
22.3334
2233322.00

Related

Error converting data type varchar to float on non varchar data type

I've come across an issue (that I've partially solved) but can't seem to find a reason behind the failing in the first place.
I have a field in a table which holds a combination of alpha and numerical values. The field is a char(20) data type (which is wrong, but unchangeable) and holds either a NULL value, 'Unknown' or the "numbers" 0, 50, 100. The char field pads the values with trailing white space. This is a known and we can't do a thing about it.
To remove the Unknown values, we have a series of coalesce statements in place, and these two return the error message as per the title.
,coalesce(DHMCC.[HESA Module Total Proportion Taught], 'Missing')
,cast(isnull(DHMCC.[HESA Module Total Proportion Taught] ,'Missing') as varchar(10))
The query I have is why am I getting this error when I'm not converting a data type of varchar to float (or am I?)
Does anyone have an idea as to where to look next to try to fix this error?
The STR() function accepts a float datatype as the first argument, therefore SQL Server is implicitly converting whatever you pass to this function, which in your case is the CHAR(20) column. Since unknown can't be converted to a float, you get the error.
If you run the following with the actual execution plan enabled:
DECLARE #T TABLE (Col CHAR(20));
INSERT #T VALUES (NULL);
SELECT Result = ISNULL(STR(Col, 25, 0), 'Missing')
FROM #T
Then checkthe execution plan XML you will see the implicit conversion:
<ScalarOperator ScalarString="isnull(str(CONVERT_IMPLICIT(float(53),[Col],0),(25),(0)),'Missing')">
The simplest solution is probably to use a case expression and not bother with any conversion at all (only if you know you will only have the 5 values you listed:
DECLARE #T TABLE (Col CHAR(20));
INSERT #T VALUES (NULL), ('0'), ('50'), ('100');--, ('Unknown');
SELECT Result = CASE WHEN Col IS NULL OR Col = 'Unknown' THEN 'Missing' ELSE Col END
FROM #T;
Result
---------
Missing
0
50
100
Missing
If you really want the STR() function, you can make the conversion explicit, but use TRY_CONVERT() so that anything that is not a float simply returns NULL:
DECLARE #T TABLE (Col CHAR(20));
INSERT #T VALUES (NULL), ('0'), ('50'), ('100');--, ('Unknown');
SELECT Result = ISNULL(STR(TRY_CONVERT(FLOAT, Col), 25, 0), 'Missing')
FROM #T
Result
------------
Missing
0
50
100
Missing
Although, since you the numbers you have stated are integers, I would be inclined to convert them to integers rather than floats:
DECLARE #T TABLE (Col CHAR(20));
INSERT #T VALUES (NULL), ('0'), ('50'), ('100'), ('Unknown');
SELECT Result = ISNULL(CONVERT(VARCHAR(10), TRY_CONVERT(INT, Col)), 'Missing')
FROM #T;
Result
---------
Missing
0
50
100
Missing
Thanks to #GarethD
I've only just come across TRY_CONVERT and this seems like the better option, so thanks him for that pointer, also trying with TRY_CAST as well.
The data really should be held in a varchar field, it's referential and not for calculation, and this seems to work equally as well,
-- Declare #varText as varchar(16) = '10 '
-- Declare #varText as char(16) = 'Unknown'
-- Declare #varText as char(16) = ''
SELECT
ISNULL(NULLIF(TRY_CAST(LTRIM(RTRIM(#varText)) as varchar(16)), ''), 'Missing') AS HESA
I've created this test scenario which works ok.

SQL - How to change data type float to nvarchar and remove scientific notation

How do I change the data type float to nvarchar in order to remove the scientific notation and still keep precision? Consider the following:
CREATE TABLE ConversionDataType (ColumnData FLOAT);
INSERT INTO ConversionDataType VALUES (25566685456126);
INSERT INTO ConversionDataType VALUES (12345545546845);
INSERT INTO ConversionDataType VALUES (12345545545257);
When I do a simple read I get the following data, as expected:
select * from ConversionDataType
ColumnData
------------------------------------
25566685456126
12345545546845
12345545545257
Now when I try update the data type to an nvarchar, it gets stored in scientific notation which is something I don't want:
update ConversionDataType
set ColumnData = CAST(ColumnData AS NVARCHAR)
The result set is as follows:
25566700000000
12345500000000
12345500000000
It replaces some digits and adds zeros after the 6th index. How can I go about this? I had a look at the Convert function but that is only for converting date time data types.
Being valid what others said in comment, if you just want to convert float to varchar without scientific notation, you need to convert to numeric. You can try this:
SELECT CAST(CAST(CAST(25566685456126291 AS FLOAT) AS NUMERIC) AS NVARCHAR)
Output:
C1
------------------------------
25566685456126292
Whereas
SELECT CAST(CAST(25566685456126291 AS FLOAT) AS NVARCHAR) AS C1
gives:
C1
------------------------------
2.55667e+016
If you need to change datatype, I think you should add a new column, update it and (if you want) delete the old column and rename the new column at the end.
CREATE TABLE TEST1 (C1 FLOAT)
INSERT INTO TEST1 VALUES (25566685456126291);
ALTER TABLE TEST1 ADD C2 VARCHAR(18)
UPDATE TEST1 SET C2=CAST(CAST(C1 AS NUMERIC) AS VARCHAR)
SELECT * FROM TEST1
Output:
C1 C2
---------------------- ------------------
2.55666854561263E+16 25566685456126292
FLOAT was a very bad decision as this is not a precise data type. If you wanted to store the phone numbers as numbers, you'd have to go for DECIMAL instead.
But you'll have to use NVARCHAR instead. And this is the only reasonable design, as phone numbers can have leading zeros or start with a plus sign. So the first thing is to introduce an NVARCHAR column:
ALTER TABLE ConversionDataType ADD ColumnDataNew NVARCHAR(30);
The function to convert a number into a string in SQL Server is FORMAT. It lets you state the format you want to use for the conversion, which is integer in your case (a simple '0'):
update ConversionDataType set ColumnDataNew = format(ColumnData, '0');
At last remove the old column and then rename the new one with the same name. SQL Server lacks an ALTER TABLE syntax to rename a column, so we must call sp_RENAME instead (at least this is what I have read on the Internet; here is a link to the docs: https://msdn.microsoft.com/de-de/library/ms188351.aspx).
ALTER TABLE ConversionDataType DROP COLUMN ColumnData;
EXEC sp_RENAME 'ConversionDataType.ColumnDataNew', 'ColumnData', 'COLUMN';
Here you can see the results: http://rextester.com/GLLB27702
SELECT CONVERT(NVARCHAR(250), StudentID) FROM TableA
StudentID is your Float Column of database
or Simply use
SELECT CONVERT(NVARCHAR(250), yourFloatVariable)

Size limit for nvarchar(max) , Print issue

I want to save XML record that length is more than 43679 char and its saved into table.
Because when i'm checking its length its giving more than 43679 char but when i'm going to read or Print data of this column its only showing 43679 char.
The below image can help you to understand the problem.
like example
declare #t table (a nvarchar(max));
insert into #t (a) values (REPLICATE(CONVERT(nvarchar(max),'a'),200000));
select LEN(a) from #t -- result 200000
select print(a) from #t -- print only 43679 char.
Please help me out of this situation.
This is a well known bug in SSMS, You can't paste more than 43679 char from a grid view column and unfortunately this limit can't be increased, You can get around this by displaying your Data in Xml format instead of nvarchar
The datatypes like NCHAR, NVARCHAR, NVARCHAR(MAX) stores half of CHAR, VARCHAR & NVARCHAR(MAX). Because these datatype used to store UNICODE characters. Use these datatypes when you need to store data other then default language (Collation). UNICODE characters take 2 bytes for each character. That's why lenth of NCHAR, NVARCHAR, NVARCHAR(MAX) stores half of CHAR, VARCHAR & NVARCHAR(MAX).
SQL Server Management Studio has a character limit when printing to the messages pane. There is a workaround to achieve what you need.
Using FOR XML to select your data using TYPE you can specify [processing-instruction] and give it a name. Your text will be presented as a link which you can open. This text will have wrappers and the name you specified. Here is an example.
declare #t table (a nvarchar(max));
insert into #t (a) values (REPLICATE(CONVERT(nvarchar(max),'a'),200000));
select LEN(a) from #t -- result 200000
SELECT a [processing-instruction(TextOutput)] from #t FOR XML PATH(''), TYPE;

Finding character values outside ASCII range in an NVARCHAR column

Is there a simple way of finding rows in an Oracle table where a specific NVARCHAR2 column has one or more characters which wouldn't fit into the standard ASCII range?
(I'm building a warehousing and data extraction process which takes the Oracle data, drags it into SQL Server -- UCS-2 NVARCHAR -- and then exports it to a UTF-8 XML file. I'm pretty sure I'm doing all the translation properly, but I'd like to find a bunch of real data to test with that's more likely to cause problems.)
Not sure how to tackle this in Oracle, but here is something I've done in MS-SQL to deal with the same issue...
create table #temp (id int, descr nvarchar(200))
insert into #temp values(1,'Now is a good time')
insert into #temp values(2,'So is yesterday')
insert into #temp values(2,'But not '+NCHAR(2012))
select *
from #temp
where CAST(descr as varchar(200)) <> descr
drop table #temp
Sparky's example for SQL Server was enough to lead me to a pretty simple Oracle solution, once I'd found the handy ASCIISTR() function.
SELECT
*
FROM
test_table
WHERE
test_column != ASCIISTR(test_column)
...seems to find any data outside the standard 7-bit ASCII range, and appears to work for NVARCHAR2 and VARCHAR2.

Unicode- VARCHAR and NVARCHAR

-- Creating Table
Create Table Test1
(
id Varchar(8000)
)
-- Inserting a record
Insert into Test1 Values ('我們的鋁製車架採用最新的合金材料所製成,不但外型輕巧、而且品質優良。為了達到強化效果,骨架另外經過焊接和高溫處理。創新的設計絕對能充分提升踏乘舒適感和單車性能。');
As I have defined data type of id as Varchar. The data is stored as ?????.
Do I have to use NVARCHAR..? What is Difference between VarChar and Nvarchar(). Please explain about UNIcode as well.
The column type nvarchar allows you to store Unicode characters, which basically means almost any character from almost any language (including modern languages and some obsolete languages), and a good number of symbols too.
also it is required to prefix N before your value. example Insert into Test1 Values (N'我們的鋁製車架採用最新的合金材料所製成,不但外型輕巧、而且品質優良。為了達到強化效果,骨架另外經過焊接和高溫處理。創新的設計絕對能充分提升踏乘舒適感和單車性能。'); or programatically use preparedstatement with bind values for inserting and updating natural characterset
Nvarchar supports UNICODE. SO yes. you need to have the column as nvarchar and not varchar.
Despite the collation of your database. Use nvarchar to store UNICODE.
Embbed your Unicode value in N'[value]'
INSERT INTO ... VALUES
('Azerbaijani (Cyrillic)', N'Aзәрбајҹан (кирил әлифбасы)', 'az-cyrl')
In DB: 59 Azerbaijani (Cyrillic) Aзәрбајҹан (кирил әлифбасы) az-cyrl
Important is the N prefix!
Valid for MS SQL 2014 I am using. Hope this helps.
Yes you have to use nvarchar or use a collation for the language set you want. But nvarchar is preferred. Goodgle can tell you what this stuff means.
Varchar uses Windows-1252 character encoding, which is for all practical purposes standard ASCII.
As others have noted, nvarchar allows the storage of unicode characters.
You can get the ASCII translations from either data type, as shown here:
IF OBJECT_ID('TEST1') IS NOT NULL
DROP TABLE TEST1
GO
CREATE TABLE TEST1(VARCHARTEST VARCHAR(8000), NVARCHARTEST NVARCHAR(4000))
-- Inserting a record
INSERT INTO TEST1 VALUES ('ABC','DEF')
SELECT
VARCHARTEST
,NVARCHARTEST
,ASCII(SUBSTRING(VARCHARTEST,1,1))
,ASCII(SUBSTRING(VARCHARTEST,2,1))
,ASCII(SUBSTRING(VARCHARTEST,3,1))
,ASCII(SUBSTRING(NVARCHARTEST,1,1))
,ASCII(SUBSTRING(NVARCHARTEST,2,1))
,ASCII(SUBSTRING(NVARCHARTEST,3,1))
FROM
TEST1
DROP TABLE TEST1