How to access variables in ScriptComponent in a DataFlow task and assign to a local variable - ssis

I am trying to access the variable RowCount. However, I can't do :
since its assign value as 0 to row count even if have a result set
var rowCount=this.Variables.RowCount;

Where are you trying to access this variable, and are you trying to update it? SSIS variables can only be written to in the PostExecute method. To do this, start by adding the variable to the ReadWriteVariables field of the script component editor, then you can access this as done below.
Your variable is named rowCount. Are you looking to return the number of rows that go through the Data Flow Task? A Script Component is called once for each record in a Data Flow Task. To get the total number of records, use Row Count transformation instead and assign the variable to the result of this.
int rowCount;
public override void PreExecute()
{
base.PreExecute();
//get variable value before processing rows.
rowCount = Variables.RowCount;
}
public override void PostExecute()
{
base.PostExecute();
//update variable after records have been procssed
Variables.RowCount = rowCount;
}

Related

SSIS script task variable value not being assigned

I have this script task I'm using to assign a value to a string variable to be used as a connection string for a flat file. The variable has a default path to a blank file containing only the header row, if the file exists in my incoming directory, the script should change the variable value to the path of that file. I've created a breakpoint and have stepped through this code line by line checking the value of files[0] at the line to assign the value to var, it contains the correct string value. Unfortunately, the variable doesn't have the changed value after the script exits. I do have the variables checked as read/write instead of just read. Any ideas where I'm going wrong?
public void Main()
{
// TODO: Add your code here
string incoming = Dts.Variables["User::DirIncoming"].Value.ToString();
foreach (Variable var in Dts.Variables)
{
if (var.QualifiedName.StartsWith("User::Conn"))
{
string varName = var.QualifiedName.Substring(10);
string[] files = Directory.GetFiles(incoming, varName + "*");
if (files.Length > 0)
{
var.Value = files[0];
}
}
}
Dts.TaskResult = (int)ScriptResults.Success;
}
I didn't realize that it mattered that my default value for my variable was being assigned via an expression, therefore I needed to change my expression instead of my value. I changed the line in question to the below code, and all is great now. Thanks everyone for taking a look.
var.Expression = $"\"{files[0]}\"".Replace("\\","\\\\");

Do not create file if 0 records

I have the following in my data flow - which in itself is in a forloop.
Is there any way in the data flow to get it to produce the file if the count of the records is zero?
I've done something similar in the past but in the control flow before the data flow, but I can't do that here as the data flow exists in a forloop to import multiple files and extract them to different files depending on the conditional split.
So if there are 56 transactions and no refunds I would like the Refunds file not to be created, but at the moment it is creating an empty file.
Thanks
You can do it in the Data Flow Task level with Script component instead of using a FF Destination.
Delete the FF destination in the Refund branch and instead add a Transformation Script Component. (Add name spaces: System.IO and System.Text)
Add the following code inside public class ScriptMain : UserComponent.
StringBuilder FileContent = new StringBuilder();
int count = 0;
public override void PreExecute()
{
base.PreExecute();
}
public override void PostExecute()
{
base.PostExecute();
if (count != 0)
{
File.WriteAllText("C:\\MyFile.txt", FileContent.ToString());
}
}
public override void Input0_ProcessInputRow(Input0Buffer Row)
{
FileContent.Append(Row.COLUMN);
count = count + 1;
}
There is no reason you can't do the same thing you've done in the past. Inside the forloop you can put a script task before the dataflow that analyzes whether the refund file will contain any records and executes logic accordingly.

How to display variable in ssis script task

I have a 'Execute SQL task' which product a row count. see screen 1.
I am trying to print 'ContactRowCount' in ssis 'Script task'. See screen 2.
But Dts.Variables["User::ContactRowCount"] is null. I can retrieve it.
Anyone knows how to retrieve variable value from 'Execute SQL task' in script task
Screen - 1
Screen - 2
Do read documentation, all of this has been covered.
Variables
I have two variables. One is for my SQL, called Quqery, which is optional. The other is an Int32 called RowCount.
Execute SQL Task
I have an Execute SQL task that uses an OLE DB Connection Manager. I have specified that it as a ResultSet of Single Row. I use my Query variable as the source.
The value is
SELECT COUNT(1) AS ContactRowCount FROM sys.columns AS SC;
In the Result Set tab, I map the 0 ResultSet to my variable User::RowCount.
If you are using a different Connection Manager provider (ADO.NET or ODBC), then these semantics all change. But it's documented.
Script Task
I ensure that I am passing in my variable as a read only object
Within my script, I need to access that variable. This is case sensitive. Furthermore, I want the .Value property. Your code, were it to work, would be casting the SSIS Variable to a string. This results in the default of the object emitting its name Microsoft.SqlServer.Dts.Runtime.Variable
Instead, we will want to access the .Value property which is returned as an object. If you were trying to do something mathematical with this value, then you'd need to convert it to an integer value but since we're going to string, that's easy.
using System;
using System.Data;
using Microsoft.SqlServer.Dts.Runtime;
using System.Windows.Forms;
namespace ST_454527867e9d448aad6a7f03563175b2.csproj
{
[System.AddIn.AddIn("ScriptMain", Version = "1.0", Publisher = "", Description = "")]
public partial class ScriptMain : Microsoft.SqlServer.Dts.Tasks.ScriptTask.VSTARTScriptObjectModelBase
{
#region VSTA generated code
enum ScriptResults
{
Success = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Success,
Failure = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Failure
};
#endregion
public void Main()
{
string strMessage = Dts.Variables["User::RowCount"].Value.ToString();
MessageBox.Show(strMessage);
Dts.TaskResult = (int)ScriptResults.Success;
}
}
}
use variable name in the script task and not the result set name.
Just check the variable values during runtime debug.

SSIS package : Store value of for loop variable in an array

I am creating an SSIS package where I have to iterate through some of the selected folder and I want to store the folder names in an array to keep track of folders that I have processed. Can I keep an array in SSIS package and keep appending the value in that array?
You can store the value of a for loop variable in an array. Doing this is a little messy IMO. There's likely a cleaner approach using "out of the box" SSIS functionality as #billinkc suggested. However, here are some pointers ...
Let's go with your scenario where you have a for each loop that iterates over some files (using a Foreach File Enumerator) and you want to store the folder names in an array.
Here are some variables we'll use:
FolderList will be the array and CurrentFile will be the for loop variable. The package in its simplest form might look like this:
In the script task, the code might look like this. I've chosen to use a List<string> as my array type, but you could use something else, such as ArrayList. (Note: you'll need to add using statements for System.Collections.Generic and System.IO for the code below):
public void Main()
{
//get current directory
string directory = Path.GetDirectoryName(Dts.Variables["User::CurrentFile"].Value.ToString());
List<string> lst = new List<string>();
// if the FolderList is already a List<string> then set set it to lst
if ((Dts.Variables["User::FolderList"].Value is List<string>))
{
lst = (List<string>)Dts.Variables["User::FolderList"].Value;
}
// if the directory isn't in the list yet, then add it to the list
if(!lst.Contains(directory))
{
lst.Add(directory);
}
// update our variable with the List<string>
Dts.Variables["User::FolderList"].Value = lst;
Dts.TaskResult = (int)ScriptResults.Success;
}
Each time the Script Task is executed, you'll get a new folder added to the array. Once the for each loop is done, you may want to examine the values of the array. You can do this using a Script Task (similar to what we did above):
List<string> lst = (List<string>)Dts.Variables["User::FolderList"].Value;
// do stuff with lst
You can also iterate over the values in the array using a for each loop (use the Foreach From Variable Enumerator), which I just learned as I was walking through this (thanks!). Just set the variable to enumerate over to your array variable (here FolderList) and specify another variable (e.g. CurrentFolder) as index 0 in Variable Mappings. This worked for a List<string>, but I'm not sure what other collection types it would work with.

SSIS: Set list variables of (1) inventorycountNr and (2) StoreNr, and then use them in a where clause

1.Script Task: set arrays of (A) inventory count and (B) StoreNr
2.Data flow task: Use the list variables in where clauses (to filter and thereby speed up performance)
*Script task must read from server A and Data flow task from server B.
I dont want to use linked server and dont want to filter downstream the dataflow, but instead want to filter through the where clauses in the dataflow source (OLE DB).
You may do it in two Data Flows.
In first:
Select value to be used in where from source table
Store this values in string variable ListToBeFetched as comma separated list using Srcipt Component as destination witch code similar to:
using System.Text;
[Microsoft.SqlServer.Dts.Pipeline.SSISScriptComponentEntryPointAttribute]
public class ScriptMain : UserComponent
{
StringBuilder sb;
public override void PreExecute()
{
base.PreExecute();
sb = new StringBuilder();
}
public override void PostExecute()
{
base.PostExecute();
Variables.IdListToBeFetched = sb.ToString().TrimEnd(',');
}
public override void Input0_ProcessInputRow(Input0Buffer Row)
{
if (!Row.Value_IsNull)
{
sb.AppendFormat("{0},", Row.Value);
}
}
}
Do the same with second list.
In second Data Flow set dynamic generated query as sql command in OLE DB Source (taken from Jamie Thomson blog):
Create a new variable called SourceSQL
Open up the properties pane for SourceSQL variable (by pressing F4)
Set EvaluateAsExpression=TRUE
Set Expression to "select * from table where columnToBeSearched in (" + #[User::ListToBeFetched] + ")"
For your OLE DB Source component, open up the editor
Set Data Access Mode="SQL Command from variable"
Set VariableName = "SourceSQL"