SSIS error printing a variable value in a C# script - sql

I'm trying to create a sample about how to catch the row count result in a variable within SSIS package and then just print the value using a simple script task.
So, first at all, I create a variable as Int32 where I'm going to store the row count result set and then I just pass through the count catch the value in a SSIS operation row count.
Then, in my Script task, I pass the variable as ReadOnly.
And finally, I type the code in the public void method to show up the current variable value.
public void Main()
{
// TODO: Add your code here
string result = null;
result = (string)Dts.Variables["qty"].Value;
MessageBox.Show("The current value of the SSIS global variable 'TestVariable' is '" + result);
Dts.TaskResult = (int)ScriptResults.Success;
}
Issues
In the image below you will see my current error in the show-up operation and also I realize that my current variable value is 0. Seems like the row count it is not getting the right value.
So guys, could you please give me a kind of guidance in order to succeded my requirement. thanks so much

SSIS usually doesn't like you performing GUI operations (such as showing a MessageBox) during processing. There are functions to display this information in the Progress Window. Have a look at componentMetaData.FireInformation().

Related

Can you build an expression inside of a custom code function in Report Builder?

I need to provide my RDL files to teammates so that they can make minor customizations for each client. One of the ways I thought I might improve the efficiency is if I could build more complex expressions inside of custom code functions so that they can input some simple arguments and have the function handle the "heavy lifting" of adjusting the expression accordingly.
This is a very simple example, and not one I would take this step for, but I thought it the easiest place to start figuring out if I can make this work. For instance, in a tablix we want a count returned based on a value where the value is customized per client (and isn't a parameter).
=Count(iif(trim(Fields!Category.Value)="OPTIONA",1,nothing))
Is there a way I could build a function so that my teammates would just need to enter the following?
=Code.CustomFunction("OPTIONA")
My understanding is that the custom code in Report Builder can't query datasets, or at least not in the way that an expression within a tablix would be able to. I've built custom functions that work with the results of an expression added as the argument, but I can't seem to wrap my head around if there's a way to construct an expression within a custom function and pass it back to the expression.
For instance:
Public Function CustomFunction(field As String) As String
Dim customExpression As String = "Count(iif(trim(Fields!Category.Value)=" & field & ",1,nothing))"
Return customExpression
End Function
As expected, this just returns a string with the text of the expression, but not an executed expression. Is what I'm trying to achieve possible with Report Builder?
Or, as an alternative approach, can I somehow place variables at the beginning of an expression that are used later so that anyone else working on the expression just needs to worry about the beginning? Essentially create multiple custom functions and call them later on?
=Code.CustomFunction("OPTIONA",Count(iif(trim(Fields!Category.Value)=Code.CustFunc01(),1,nothing)))
Honestly not sure how I would go about building the functions themselves from here.
You can use a function instead of the related field. The function takes the field string as an argument and the filter string for which will increase the counter. Finally it returns the original field value
Private Dim Counter As Integer
Public Function SetCounter( Expr As String, Filter As String) As String
If Expr = Filter Then Counter = Counter + 1
Return Expr
End Function
Public Function GetCounter( ) As Integer
Return Counter
End Function
For the field value you can use the following expression (yellow color)
=Code.SetCounter( Fields!MyString.Value,"OPTION A")
To get the counter value you can either use the following expression calling a function (orange color)
= Code.GetCounter()
Or make the variable public and use Code.Counter as the expression

C# SQL: get sql connection try attempt

I am trying to get the number of the try attempt of a SQLConnection to inform the user about those attempts.
Below you can see the code, where magic should happen. 'i' would be the number of the attempt. The connection 'con' throws a lot of SqlExceptions, but i can't catch them like shown below. 'databaseConnection' represents the connectionstring. It is currently empty for testing purposes.
I bet, that i am missing something, but I can't figure out what, since I'm new to SQL programming in C#.
"txtProgressbarWorking" is a label in the UI.
int i = 1;
con = new SqlConnection(databaseConnection);
try
{
con.Open();
}
catch(SqlException s)
{
txtProgressbarWorking.Content = "Connecting... " + (++i);
}
There are several things wrong with this code:
1) Are you calling this in some sort of loop? If not, your i variable won't be incremented.
2) SqlConnection.Open() throws several kinds of exceptions - not just SqlException, which I assume is why you "can't catch them" all as you mentioned. You should ideally specify each exception or catch the higher-level System.SystemException.
3) Your code to increment the progress bar is in the catch-block of your exception handler, and will only be executed if the exception is caught. If you are in fact calling this code in a loop, you would want to move the code in the catch-block into the try-block instead.
4) Your ++i should be i++ so that i is incremented after the statement; either that, or initialize i to zero instead of 1. The way you have it now, the first value from i in your catch-block would be 2.
I suggest you take a look at [MSDN's documentation on SqlConnection.Open Method ()][1]
https://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlconnection.open%28v=vs.110%29.aspx

Pentaho: How to dynamically add Field (= Column) to OutputRow?

I would like to dynamically add fields (or a new columns) to the resulting output row in Kettle.
After spending hours reading through froum posts and he not so well done scripting documentation, I wondered if Stackoverflow would be of any help.
We can use the below steps to generate Dynamic column generation:
calculator
add constants.
Select required fields in table input and assign those values as a set variable and second transformtion level use get variables hop
How are your input values passed to the SQL query? if they are variables then just pass the table input step to a "get variables" step and get your new columns in that way.
Alternatively you can add columns using either calculator or add constants.
Or you could even use the "get system info" step to get commandline args and dates etc.
First, let me give you a code snippet of what I have in a User Defined Java Class step:
private int fieldToHashGeoIndex;
private int fieldToHashHeadIndex;
public boolean processRow(StepMetaInterface smi, StepDataInterface sdi) throws KettleException
{
Object[] r=getRow();
if (r==null)
{
setOutputDone();
return false;
}
if (first) {
fieldToHashGeoIndex = getInputRowMeta().indexOfValue(getParameter("FIELD_TO_HASH_GEO"));
if (fieldToHashGeoIndex<0) {
throw new KettleException("Field to hash not found in the input row, check parameter 'FIELD_TO_HASH_GEO'!");
}
fieldToHashHeadIndex = getInputRowMeta().indexOfValue(getParameter("FIELD_TO_HASH_HEAD"));
if (fieldToHashHeadIndex<0) {
throw new KettleException("Field to hash not found in the input row, check parameter 'FIELD_TO_HASH_HEAD'!");
}
first=false;
}
Object[] outputRowData = RowDataUtil.resizeArray(r, data.outputRowMeta.size());
int outputIndex = getInputRowMeta().size();
String fieldToHashGeo = getInputRowMeta().getString(r, fieldToHashGeoIndex);
String fieldToHashHead = getInputRowMeta().getString(r, fieldToHashHeadIndex);
outputRowData[outputIndex++] = MurmurHash.hash64(fieldToHashGeo);
outputRowData[outputIndex++] = MurmurHash.hash64(fieldToHashHead);
putRow(data.outputRowMeta, outputRowData);
return true;
}
Now, normally you configure outputRowMeta from the step's config, but maybe you can modify it in the code. This should allow you to specify additional fields in the code.
As an alternative, you could latch on variable fields by defining fixed output fields on to the step like 'field1', 'field2', etc. and tracking the names of the fields elsewhere. You'd probably have to make all the fields of type String and then do your own type adjustments later.
Now that I think of it, though, variable output fields may lead to trouble: you have to be very careful with what you do in later steps to avoid having errors due to type mismatches or missing fields.

how to store sql query result in a variable and messegeBox

I have a simple sql query in my Execute sql task in ssis package,
SELECT MAX(binindex)
FROM dbo.myTable
I need to store this maximum index into a variable and then pass it to Script Task and display it,
I already declared a package variable, the package compiles, however it shows -1 every time, I don't know what I'm doing wrong, any help will be appreciated!
public void Main(){
//TODO: Add your code here
Dts.TaskResult = (int)ScriptResults.Success;
MessageBox.Show(Dts.Variables["User::BININDEX"].Value.ToString());
}
The good news, is that you are doing everything correctly as far as I can see. I recreated your package and I get the expected value from my query.
I can also induce your situation - the correct value is returned from my query but my package produces an "incorrect result."
The problem, I hope, is that you have two BININDEX variables defined at different scopes. My original assumption was the Package scoped one contained a value of -1 and you had a variable scoped to the "Execute SQL Task" with the same name. The default behaviour is a variable is created scoped to the object that currently has focus. This changes in the 2012 release of SQL Server by the way.
As your picture shows a design-time value of 123 for the package scoped variable, the possibility also exists that you have a variable defined on the Script Task with the same name of BININDEX. The local variable would override the globally scoped variable
Click on your Script Task and hopefully you'll see a BININDEX defined there like the above. Otherwise, I think the problem is somewhere in your package, you have conflicting BININDEX variables. You can try slogging through the Package Explorer looking for an instance where you have two variables with the same name listed.
I need to leave but if none of that is the case, add a PostExecute breakpoint on the Execute SQL Task and look at your Locals window (not Variables as that only reflects Design-time values). Expand Variables and you should be able to see the value of BININDEX. Is it correct there?

loading serialized data into a table

For an answer to another question, I wanted to load some serialized lua code into a table. The string to be loaded is of this form:
SavedVars = { }
SavedStats = { }
(where each of the {...} might be any Lua expression, including a table constructor with nested data. I'm assuming it is not calling any (global) functions or using global variables.
What I finally want to have is a table of this form:
{ ["SavedVar"] = { }, ["SavedStats"] = { } }
I do not want to have global variables SavedVars afterwards.
How to do this most elegantly?
(I already found a solution, but maybe someone has a better one.)
Here is my solution:
-- loads a string to a table.
-- this executes the string with the environment of a new table, and then
-- returns the table.
--
-- The code in the string should not need any variables it does not declare itself,
-- as these are not available on runtime. It runs in a really empty environment.
function loadTable(data)
local table = {}
local f = assert(loadstring(data))
setfenv(f, table)
f()
return table
end
It loads the data string with loadstring and then uses setfenv to modify the global environment of the function to a new table. Then calling the loaded function once fills this table (instead of the global environment), which we then can return.
Setting the environment to a new table has the effect that the code can't use any global data at all. I think this is a good way to sandbox the code, but if it is not wanted, you could populate the table before or provide it with some metatable (but unset it before returning the table).
This loading function will also work with serialized data produced like in Saving Tables with Cycles.