How are SSIS Precedence Constraints Evaluated? - sql-server

Maybe this question seems very basic and elementary but I need some clarification.
In SSIS the following Constraints are available to control component execution flow:
Logical AND. All constraints must evaluate to true.
Logical OR. At least one constraint must evaluate to true.
I have a very simple package I am using to test the conditions described.
A Process Task - calls a batch file that returns a string value and exit code.
The Process Task receives the value from the batch file as a StandardOutputVariable and assigns it to my user defined variable User::BatchExecutionCode
A Script Task - for validation, displays the acquired value from my user variable so I can visually see and affirm that the expected value is getting passed
An Execute SQL Task - That simply does a SELECT GETDATE().
I have setup a Logical AND condition between the Script Task and Process Task that mandates:
Constraint - Task execution must "Complete"
Expression - #BatchExecutionCode == "0"
When I execute, both tasks prior to the final "Execute SQL" task complete and I get a visual message box showing the value of my variable as "0" but the execution just stops afterward and never executes the last task after evaluation.
What is the problem? According to the stated conditions for execution, the conditions have been met. So exactly how are the precedence constraints being evaluated.
EDIT: For clarification, In the screenshot the value of #BatchExecutionCode has been passed to User::Result variable via the Script Task. Thats why the Expression says #Result == "0". Either way, the results is still the same

The only reason should be #Result doesn't equal "0", you can confirm that with a post execute breakpoint on you script task.
You can use the following article to confirm what's really in this variable.
http://www.jasonstrate.com/2011/01/31-days-of-ssis-using-breakpoints-231/

Related

SSIS: Precedence Constraint not working as expected

Referring to the below snapshot, I am trying to use "Logical AND All constraint must be evaluated to true". In Expression, I am trying to equate Variable value with the current date and when checking it on evaluation expression it shows true when the condition is matching but still while running the package it doesn't move to the next step.
Expression used:
#[User::LastUpdated] == (DT_DBDATE) GETDATE()
Please help on this issue. Thanks.
The second screenshot shows that the Script Task is executed successfully which means that the first constraint is met. You should make sure that the #[User::LastUpdated] date value is equal to (DT_DBDATE)GETDATE().
Hint: Make sure that the #[User::LastUpdated] date value does not include the time part. You can use the following expression to avoid the time part problem:
(DT_DBDATE)#[User::LastUpdated] == (DT_DBDATE)GETDATE()

How to keep SSIS variable static during the package execution

I have a SSIS package which reads from the MSSQL database and saves it into a xlsx file.
I dynamically change the extract with the following format: [filename - ddmmyyyy hhmm].xlsx
problems is this: my SSIS package creates a file like [filename - 18052021 1400].xlsx
however when it tries to email it for example, the time is now 1401 and it tries to find a file name like [filename - 18052021 1401].xlsx which does not exist and so it generates an error.
Is there any way to keep the variable static through the execution?
Many thanks,
The problem you're experiencing is that every time a variable with an Expression is read, it is evaluated. I vent about this from time to time in my answers because it can be an insidious little problem to track down.
Currently, you are building a file name something like
"FileName - " + (DT_WSTR, 2) day(getdate()) ...
The problem as I've already hinted and you're experiencing is that every time that expression is evaluated, SSIS checks the current time. If your package runs for more than a minute, you'll have crossed the boundary and now have a "new" name to deal with.
The way to resolve it, is to use a System scoped variable, #[System::StartTime], instead of the getdate
"FileName - " + (DT_WSTR, 2) day(#[System::StartTime])) ...
StartTime is the time the package itself starts. It could run for a minute or a day and the value will remain constant because it's what you expect - the time the package started.
If you need something that can change but remains constant for a specific scope, put all the pieces in a Sequence Container and then you can make use of a System scoped variable named (approximately) ContainerStartTime. The container (sequence, foreach, for) only has one start time but it can be 10 minutes later than the package itself started.
Presumably your variable's value is an expression then, not a Value? If so, then don't use an Expression for the variable, assign it a value, and then assign a new value of the variable at the start of your SSIS package using a expression Task. Without the variable name, nor your expression, I can't give the exact solution, but the expression task would have an expression like:
#[User::YourVariableName] = {Your original Expression}

SSIS Script task base result on path

I have a SSIS Package and the first task I have is a script task. it checks to see if a file exists if it does (=1) then it continues to next tasks how to I get it to go down a different route if file does not exist(=0)?
I have tried adding a completion arrow and a failure arrow but this is not correct
Use the following steps
Add a variable to the ssis package of type boolean
if file exists set variable = true
in the success arrow (double click on it) and choose constraint and expression option
in the expression add #[User::variable] == True and add another success arrow with #[User::variable] == False
Read more at the following links:
Add Expressions to Precedence Constraints
How to implement Conditional Split in Control Flow of SSIS
Working with Precedence Constraints in SQL Server Integration Services

SSIS: execute first task if condition met else skip to next

I am getting to know SSIS, I apologize if the question is too simple.
I got a set of tasks inside a foreach-loop-container.
The first task needs only to get executed on condition that a certain user variable is not null or empty.
Otherwise, the flow should skip the first task and continue to the second one.
How would I go about realizing this (in detail) ?
Issue 1: There are two ways to interpret your logic: "...a certain user variable is not null or empty":
The (Variable is Not Null) OR the (Variable is Empty).
The (Variable is Not Null) OR the (Variable is Not Empty).
It's all about the object(s?) of the word "not". The differences are subtle but will impact when the first task in the Foreach loop executes. For demonstration purposes, I am assuming you intend #1.
Issue 2: The first task can no longer be first. In order to accomplish what you desire using SSIS inside the BIDS environment, you need to place another task ahead of the task formerly known as "the first task". This is so you can set a Precedence Constraint on the former first task from the new first task.
It is possible to accomplish what you desire by designing your SSIS dynamically from managed code, but I don't think this issue warrants the overhead associated with that design choice.
I like using an empty Sequence Container as an "Anchor" task - a task that exists solely to serve as the starting endpoint of a Precedence Constraint. I heavily document them as such. I don't want anyone deleting the "unnecessary empty container" and roaming the halls for days shaking their heads and repeating "Andy, Andy, Andy..." but I digress.
In the example below, I have two precedence constraints leaving the empty Sequence Container. One goes to the task that may be skipped and the other to the task following the task that can sometimes be skipped. A third precedence constraint is required between the task that can sometimes be skipped and the task following. It is important to note this third precedence constraint must be edited and the Multiple Constraints option set to OR. This allows the task following to execute when either of the mutually exclusive previous paths are taken. By default, this is set to AND and will require both paths to execute. By definition, that will not - cannot - happen with mutually exclusive paths.
I test the value of an SSIS String variable named #MyVar to see if it's Null or Empty. I used the Expression Only Evaluation Option for the constraints leaving the empty Sequence Container. The expressions vary but establish the mutual exclusivity of the expression. My Foreach Loop Container looks like this:
I hope this helps.
:{>
The best thing can be to use the 'Disable Property' in expressions and giving the expression as per the condition. Just search how to use the disable property.
How about a simple solution instead of some of the more complex ones that have already been given. For the task you want to conditionally skip, add an expression to the disabled property. Any expression that produces a true or false result will work, so for the question example you could use:
ISNULL(#[User::MY_VAR]) || #[User::MY_VAR]==""
The only downside is that it may not as visible as some of the other solutions but it is far easier to implement.
I would create a For Loop Container around the task that needs the condition with the following conditions (#iis the loop counter, #foo is your user variable that you want to test):
InitExpression: #i=0
EvalExpression: #i<1 && !ISNULL(#Foo) && #Foo!=""
AssignExpression: #i=#i+1
there is no need to create a "script"
I think the best (and simpler) approach is to add a blank script task inside your loop container before your "first task", drag the green arrow from it to your "first task" (which obviously will become the second) and use the precedence constraint to do the check.
To do that, double click the arrow, select "expression" on the "evaluation operation" and write your expression. After hitting OK the arrow will become blue indicating that it isnt a simple precedence constraint, it has a expression assigned to it.
Hopefully I didn't misunderstand the question but a possible solution can be as written below.
I created a sample ForEach loop. The loop itself is an item enumerator. It enumerates the numbers 1, 2, 3. The acutal value is stored in a variable called LoopVariable.
There is another variable named FirstShouldRun which is a Boolean variable showing the first task in the foreach loop should be runned or not. I set this variable's EvaluateAsExpression property to true, and its expression is (#[User::LoopVariable] % 2) == 0. I would like to demonstrate with this that every second time the first task should be started.
The two tasks do nothing much but display a MessageBox showing the task has been started.
I started the package and first and the third time the first task didn't started. In the second loop the MessageBox (showing "First started") appeared.
After that you should set FirstShouldRun variable as you like.
As I mentioned in my first comment to the OP, this solution is based on the idea of Amos Wood written in another answer.
That's a bit tricky.
You have to create a Script Task and check if your variable is not null in there.
So first you have the script task in which you will have the following code in your Main() function:
public void Main()
{
if (Dts.Variables["User::yourVariable"].Value != null)
{
Dts.TaskResult = (int)ScriptResults.Failure;
}
else
{
Dts.TaskResult = (int)ScriptResults.Success;
}
}
Then you create two connections from your script task, one to the task that needs to be executed when your variable is not null, and one to the next task (or to another script, if you need to check again, if the variable is not null).
Then you right-click on the (green) arrow of your first connection and select "Failure". Right-click the connection to the next task / script and set it to "Completion".
It should then look something like this:
That's it.

How to modify the variable in SSIS?

I have a simple String variable with the following value: "C:\Test.txt".
Now I would like to edit the variable to point to a different file.
I cannot find a way to do that. I can change the Name, Data Type, but not the value itself!
Do I need to delete the variable and create the new one?
Update: The problem was caused by "ReadOnly" property set to "True". For typical scenarios, see the accepted answer below.
As #Yuck and #devarc have noted, there are two different and distinct values a Variable holds. The Design-time value is the value you assign when the variable is first created. In your case, the variable holds C:\Test.txt as the design-time value. Everytime you open the package, it would show C:\Test.txt until you change it in the
To make the value of a variable change while the package is running, your options are either to set the value or calculate it. Here I have created a package-level variable CurrentFile with the value of C:\Test.txt
One thing that often trips people up is that they have correctly changed the run-time value but when they run it in BIDS, they see the "old" value. The value displayed in the Variables window does not change during package execution.
During package execution, my Variables window still shows the design-time value (C:\Test.txt) but the true value is reflected in the Locals window (C:\Test2.txt)
Setting a value
The value of most anything in SSIS can be established at run-time through a set of verbose command-line options or through configuration sources. The biggest difference in my mind is that this approach is that the value will always be the value for the entire lifetime of package execution. Sequential or parallel invocations of a package can change that value but for that execution the value would remain constant (barring an explicit modification of the value.
/SET
Command-line execution (dtexec.exe), right clicking on a package and running from the filesystem (dtexecUI.exe) or creating a SQL Agent job step of SQL Server Integration Services all allow for providing a run-time value through the SET command. Using the above variable, the following command would set the run-time value to C:\Test2.txt
dtexec /file C:\Generated.dtsx /set \Package.Variables[User::CurrentFile].Properties[Value];"C:\Test2.txt"
Configuration
SSIS offers an option to create configuration sources to provide run-time values to packages. The article I linked to above does a much better job describing the pros and cons of the configuration options than I will do here. I will say that I typically use both - my SET command configures a connection manager which is then used by the package to find the "full" set of package configurations.
Calculating a value
There are a variety of tasks in SSIS that can change the value of a variable as well as the use of Expressions to change a value. I see these as things that operate on value whilst the package is in flight.
Tasks
A Script Task is one of the most commonly used mechanisms for those starting out but I find other tools in the SSIS toolkit usually better suited for changing variable values.
Foreach Loop Container and Execute SQL Task are two of the other big Tasks you should look at for assignment of a variable value.
Expressions
Expressions are the most glorious candy in the SSIS toolbox. Most every "thing" in SSIS exposes properties for configuration. That's helpful, but using assigning an expression to build those properties is outstanding.
For example, imagine 3 variables RootFolder, FileName and ComputedCurrentFile with values of C:\, File2.txt and empty string. On the Properties window for ComputedCurrentFile we'd change the value for EvaluateAsExpression from False to True and then use an expression like #[User::RootFolder]+ "\\" +#[User::FileName] That simply concatenates the value the first two variables together. This can be helpful if the file name for processing was standard but the source folder changed often. Or if we're talking about output, it's common to use expressions to build an output file name using the date and possibly time of when the package is running.
Finally, there is nothing that prevents a mixing and matching of these approaches. I typically use a configuration to point a file enumerator at the correct starting folder and then use calculated values to identify the current file for processing.
If you want to change it in designer just right click on free space and --> Variables.
But if you want to change it at runtime I suggest you to:
create script task
choose language
add your variable to ReadWriteVariables.
Edit script.
For example in VB:
Dts.Variables("myVariable").Value = #"C:\Test2.txt";
Dts.TaskResult = ScriptResults.Success
Found an easy way to handle this. Remove the Variable from Expression which will enable Value Box to edit. Once it is edited, add the Variable back in the Expression should get the updated value. Hope this helps.
I was also facing the same issue like you where once the variable is declared and define (for eg:var1=text1.csv)in SSIS Variable window I was not able to update the variable value(for eg: var1=text2.csv) in SSIS Variable Window by clicking on the variable value field.
Applied below fix:-
I noticed that I was using var1 variable as a Expression by using expression builder so to update the value(for eg:-var1=text2.csv) I used expression builder window.once you done using the expression builder,you can see the text2.csv is got mapped to var1.

Resources