Why does this SSIS Conversion Expression syntax the way it is? - sql-server

I'm looking at an SSIS package with a Derived Column Data Flow Component
When, I open it, I see 1 transformation:
Derived COLUMN Name : CLIENT_ID
Derived COLUMN: "REPLACE 'CLIENT_ID'"
EXPRESSION: TRIM(CLIENT_ID) == "" ? (DT_STR,9,1252)NULL(DT_STR,9,1252) : CLIENT_ID
DATA TYPE: string [DT-STR]
LENGTH: 9
PRECISION:
SCALE:
CODE PAGE: 1252 (ANSI- LATIN I)
I'm trying to understand the SSIS expression and I'm not sure that I understand the syntax.
TRIM(CLIENT_ID) == "" ? (DT_STR,9,1252)NULL(DT_STR,9,1252) : CLIENT_ID
I believe that the code is reading in the CLIENT_ID field from a flat file and that the field is coming in as a string. The conversion appear to check to see if the value read is all whitespace and if so, converts to a NULL string value, otherwise uses the original CLIENT_ID string value.
The syntax of the conversion confused me, perhaps because I am trying to relate it to C# code. I expected the following for the EXPRESSION:
TRIM(CLIENT_ID) == "" ? NULL : CLIENT_ID
or perhaps
TRIM(CLIENT_ID) == "" ? (DT_STR,9,1252)NULL : CLIENT_ID
Why is NULL surrounded by two conversions: (DT_STR,9,1252)?

SSIS has a separate null for each datatype. E.g., NULL(DT_STR,9,1252) means a null that is specific to a nine character string on that code page.
As in C#, the first (DT_STR,9,1252) is a type cast. Of course, the cast is not necessary here, since this NULL already has the correct data type.

Related

SSIS Package - Derived Column Conditional Expression for Date Fields with Zero

I am relatively new to SSIS and its data types. I have successfully created a Data Flow task that imports data from a comma-delimited .txt flat file to SQL Server. An error occurs when running the task, at the point where a date field in the .txt file has 0.
For a Derived Column expression to convert the date fields with 0 to Null, I have come up with the following so far...
[Latest Bill Due Date]==0 ? NULL(DT_DATE) : (DT_DATE)[Latest Bill Due Date]
...but the logic isn't accepted and the error message appears:
The data types "DT_WSTR" and "DT_I4" are incompatible for binary operator "==". The operand types could not be implicitly cast into compatible types for the operation. To perform this operation, one or both operands need to be explicitly cast with a cast operator.
Thanks in advance for any direction.
I had a similar problem, when in a textfile there was a 00000000 value, had to convert it to null in a datetime column. What ended up working for me was stablishing the table with null value as default in the column and also adding a Script Component as Transformation. Add as a column output something like 'VerifyNullDateVar' and inside the script do something like
if (Row.DATEVAR == 0)
{
//do whatever you want to do if the input value is an actual date
Row.VerifyNullDateVar = 2;
}
else
Row.VerifyNullDateVar = 1;
DATEVAR is the input column you get from the textfile. After that, use a derived column to read the value from VerifyNullDateVar
VerifyNullDating == 1
VerifyNullDating == 2
Finally, you need to set up 2 OLEDB Destination, one when you can save a date value in the Table; and the other one when you ont save anything in it, that way it gets the default null value

SSIS Derived Column - Text in Numeric Field is not converting

I'm importing thousands of csv files into an SQL DB. They each have two columns: Date and Value. In some of the files, the value column contains simply a period (ex: "."). I've tried to create a derived column that will handle any cell that contains a period with the following code:
FINDSTRING((DT_WSTR,1)[VALUE],".",1) != 0 ? NULL(DT_R8) : [VALUE]
But, when the package runs it gets the following error when it reaches the cell with the period in it:
The data conversion for column "VALUE" returned status value 2 and status text
"The value could not be converted because of a potential loss of data".
I'm guessing there might be an escape character that I'm missing in my FINDSTRING function but I can't seem to find what that may be. Does anyone have any thoughts on how I can get around this issue?
Trying to debug things like this is why I always advocate adding many Derived Columns to the Data Flow. It's impossible to debug that entire expression. Instead, first find the position of the period and add that as a new column. Then you can feed that into the ternary operation and bit by bit you can add data viewers to ensure you are seeing what you expect to see.
Personally, I'd take a different approach. It seems that you'd like to make any columns that are . into a null of type DT_R8.
Add a derived column, TrimmedValue and use this expression to remove any leading/trailing whitespace and then
RTRIM(LTRIM(Value))
Add a second derived column component, this time we'll add column MenopausalValue as it will remove the period. Use this expression
(TrimmmedValue == ".") ? Trimmedvalue : NULL(DT_WSTR, 50)
Now, you can add your final Derived Column wherein we convert the string representation of Value to the floating point representation.
IsNull(MenopausalValue) ? NULL(DT_R8) : (DT_R8) MenopausalValue
If the above shows an error, then you need to apply the following version as I can never remember the evaluation sequence for ternary operations that change type.
(DT_R8) (IsNull(MenopausalValue) ? NULL(DT_R8) : (DT_R8) MenopausalValue)
Examples of breaking these operations into many steps for debugging purposes
https://stackoverflow.com/a/15176398/181965
https://stackoverflow.com/a/31123797/181965
https://stackoverflow.com/a/33023858/181965
You can do it like this:
TRIM(Value) == "." ? NULL(DT_R8) : (DT_R8)Value

Insert/transform to 0 or 1 based on presence of text

I'd like to insert to a table's bit column either 0 or 1, 0 where there is no text, 1 where there is. I am pulling data through an excel source in SSIS. In the example below, it should go:
Client 1: 1 1 1
Client 2: 1 0 1
How it looks in excel:
Products: Ball Bicycle Bat
Client 1: Ball Bicycle Bat
Client 2: Ball Bat
Client 3: Ball
Client 4: Bicycle Bat
Any way to achieve this in SSIS?
You'll need to use a few items to accomplish this.
How do I add new columns to a data flow task?
A Derived Column will allow you to create these new boolean columns. A derived column uses an Expression to compute a value. You'll need to specify the column name when you create a new one. You'll also want to ensure the data types are as expected.
What's my expression?
The first is whether the no text comes in as NULL, an empty string or a padded string. Knowing whether the current row satisfies one of those conditions will tell us whether we need to make our new column 1 or 0.
A value is either NULL or NOT NULL. If it's not null, then we need to worry about whether it's empty/padded. We test for NULL via the ISNULL expression.
A boolean OR is expressed as ||
An equality test is done via ==
We check for an empty string using the LEN expression.
We need to remove all the trailing spaces from our column to see if it reduces down to an empty string. We'll use RTRIM to accomplish this.
An Expression must evaluate to something, but we have conditional (if) logic. The way we work around that is the ternary operator (boolean test) ? (true expr) : (false expr)
The SSIS system data type for boolean is DT_BOOL
A cast is performed by (DT_TYPE) VALUE
Putting it all together
Add a derived column component to your data flow. Make the column name Col1HasText
Line breaks added for readability
(isnull([Col1]) || LEN(RTRIM([Col1])) == 0) ?
((DT_BOOL) 0) :
((DT_BOOL) 1)
English version: If Col1 is null or if the length of the right-trimmed version of Col1 is zero, then we want to cast one to a data type of DT_BOOL (boolean). Otherwise, cast zero to a data type of DT_BOOL

SSIS Flat File with Numeric DataType with Spaces

I'm using SSIS to load a fixed length Flat File into SQL.
I have a weight field that has been giving me trouble all day.
It has a length of 8 with 6 DECIMAL POSITIONS IMPLIED (99V990099).
The problem i'm having is when it isn't populated and has 8 spaces.
Everything i try gets an error:
"Invalid character value for cast specification"."
OR
"Conversion failed because the data value overflowed the specified type.".
OR
Data conversion failed.
The data conversion for column "REL_WEIGHT" returned status value 2 and status text
"The value could not be converted because of a potential loss of data.".
I've tried declaring it as DT_String & DT_Numeric.
I've tried many variations of:
TRIM([REL_WEIGHT])=="" ? (DT_STR,8,1252)NULL(DT_STR,8,1252) : REL_WEIGHT
ISNULL([REL_WEIGHT]) || TRIM([REL_WEIGHT]) == "" ? (DT_NUMERIC,8,6)0 : (DT_NUMERIC,8,6)[REL_WEIGHT]
TRIM(REL_WEIGHT) == "" ? (DT_NUMERIC,8,6)0 : (DT_NUMERIC,8,6)REL_WEIGHT
But nothing seems to work.
Please someone out there have the fix for this!
I think you may be running afoul of the following point, explained nicely at http://vsteamsystemcentral.com/cs21/blogs/applied_business_intelligence/archive/2009/02/01/ssis-expression-language-and-the-derived-column-transformation.aspx:
You can add a DT_STR Cast statement to the expression for the MiddleName, but it doesn't change the Data Type. Why can't we change the data type for existing columns in the Derived Column transformation? We're replacing the values, not changing the data type. Is it impossible to change the data type of an existing column in the Derived Column? Let's put it this way: It is not possible to convert the data type of a column when you are merely replacing the value. You can, however, accomplish the same goal by creating a new column in the Data Flow.
I've solved this on past occasions by loading the data from the flat file as strings, and then deriving a new column in a Derived Column transformation which is of numeric type. You can then perform the appropriate trimming, validation, casting, etc. in the SSIS expression for that new column in the transformation.
Here, I found an example SSIS expression I used at one point to derive a time value from a 4-digit string:
(ISNULL(Last_Update_Time__orig) || TRIM(Last_Update_Time__orig) == "") ? NULL(DT_DBTIME2,0) : (DT_DBTIME2,0)(SUBSTRING(TRIM(Last_Update_Time__orig),1,2)+":"+SUBSTRING(TRIM(Last_Update_Time__orig),3,2)+":00")
There has to be a better way to do it, But i found a way that works.
Create a Derived Column Expression:
TRIM(REL_WEIGHT) == "" ? (DT_STR,9,1252)"0.0000000" : (DT_STR,9,1252)(LEFT(REL_WEIGHT,2) + "." + RIGHT(REL_WEIGHT,6))
THEN Create a Data Conversion Task to change it to Numeric and set scale to 6.
And then Map the [Copy of NewField] to my SQL table field set up as Decimal(8,6).
I don't know how the performance will be of that when loading a million records, probably not the best. If someone knows how to do this in a better way performance wise please let me know.
Thanks,
Jeff

SSIS Converting a char to a boolean/bit

I have an SSIS package to load data; as you may recall there are flags that are in data files as Y/N char(1) when I am trying to load them as bit flags into SQL Server. I am specifying the columns in the data file as String [DT_STR] and I have a data conversion task to convert them to booleans based on the following expression (I received the same conversion error just specifying them as DT_BOOL to begin with, despite SSIS asking me to say what values it should consider as boolean):
[ColumnName] == "Y" ? (DT_BOOL)1 : (DT_BOOL)0
Running the package gives an error and tells me Invalid character value for cast specification and The value could not be converted because of a potential loss of data on the actual import to SQL Server (via an OLE DB Destination).
What am I missing here to get it to properly convert?
Try this:
(DT_BOOL)([ColumnName] == "Y" ? 1 : 0)
This also has the advantage of automatically setting the data type of the derived column correctly.
I was able to solve it by using a derived column and, instead of replacing the char columns, creating new columns set to type of DT_BOOL like so:
[Recycled] == "Y" ? True : False
I had the same problem with
(DT_BOOL)([ColumnName] == "Y" ? 1 : 0)
and I could only get it to work by taking OUT the "(DT_BOOL)" portion out of the expression and putting the job of converting it to a boolean onto the "Data Type" part by selecting "Boolean [DT_BOOL]. No problems after that.

Resources