How to dowhile loop in camel context with expression containing sql query? - apache-camel

Wanted to add some portion of route in loop so that it executes again and again till the sql query returns some value. And loop must end if no data is returned by sql query.

its a example about sql it is not good scenario but you can change it for yourself
CamelSqlRowCount = The number of rows returned for select operations, returned as an Integer object. This header is not provided when using outputType=StreamList.
from("direct:start")
.loopDoWhile(simple("${headers.CamelSqlRowCount} <= 5"))
.to("mock:loop")
.to('sql:select * from student where id=1')
.end() // end loop
.to("mock:result");

Related

How do I configure a foreach loop container in SSIS to take defined start and end dates and run for each date in between?

I'd like to define start_date and end_date parameters in my SSIS package, and have a foreach container that runs for each date in between these 2 (inclusive), which executes a SQL query taking in the current date value (ie starting at start_date) and using it as a parameter for the query.
I'm quite new to SSIS programming and I cannot find information on how to do this.
You can simply add a for loop container and use these variables as mentioned in the image below:
Where #[User:Loop], #[User:MinDate], #[User::MaxDate] are of type System.DateTime
image reference
How do I loop through date values stored as numbers within For Loop container?
Passing parameters to Execute SQL Task
You can refer to the following posts for more details:
Passing Variables to and from an SSIS task
How to pass variable as a parameter in Execute SQL Task SSIS?
A For Loop would be the better option to do this. Assuming that the start and end dates as supplied as parameters to the package as indicated in your question, be aware that parameters cannot be updated in an SSIS package however variables can be. This, as well as an example of the process outlined in your question, is further detailed below.
Create an SSIS datetime variable. As mentioned earlier, this will be used to store in initial value of the start date parameter.
Next add a For Loop on the Control Flow. In the screenshot below, the variable #[User::vStartDate] is set to the same value as the package parameter #[$Package::pStartDate] in the InitExpression on the For Loop. Iterations of the loop continue while the start date variable is less than/equal to the end date parameter, which is specified in the EvalExpression field.
After the Execute SQL Task (or however the SQL query is executed) add a Script Task. This will increment the value of the start date variable, so make sure this is the last task in the loop. An example C# script is below, which simply sets the value of the start date SSIS variable to a C# variable, increments the C# variable by one day, then writes that value back to the SSIS variable. Make sure to add the SSIS start date variable in the ReadWriteVariables field on the Script Task. This will go in the Main method of the script as follows. Although there’s just an increment of the date and update of the variable done in the Script Task, having this in place will allow for easier sustainability in the long term in case more logic needs to be added to this as C# provides much more functionality.
Script Task:
public void Main()
{
//get value in current iteration of loop
DateTime currentIterationValue = Convert.ToDateTime(Dts.Variables["User::vStartDate"].Value);
//increment by one day
currentIterationValue = currentIterationValue.AddDays(1);
//update SSIS variable
Dts.Variables["User::vStartDate"].Value = currentIterationValue;
Dts.TaskResult = (int)ScriptResults.Success;
}
I used an Execute SQL Task to store the dates (results) as a Result Set in a user defined variable. Then, inside the foreach loop container, I used the foreach ADO Enumerator on the user defined variable which has the set of dates. Using the variable mapping in the foreach loop container, you can map the start_date and end_dates from the user defined variable and pass it to other variables.
For example:
I have a SELECT statement which selects 2 rows with columns start_date and end_date. This will be stored as a result set in a variable called "main_dates". The foreach ADO Enumerator will enumerate on this "main_dates" variable (for each row in main_dates run the for loop). Then in the Variable Mapping section, you can create 2 new variables called u_start_date and u_end_date and map the columns 0 and 1 to these variables.
Inside the foreach loop whenever you execute a stored procedure, you can pass the u_start_date and u_end_date variables as parameters.

For each container not failing when it is returning 0 rows

I have a for each container in my SSIS package.Inside that i have a script task in it.For each loop is iterating an object variable containing result from an Execute SQL task.
Everything is fine but the problem is for-each loop is not failing even when no rows are returned by previous sql task.
I want the package should fail when zero rows are returned.What should id do?
I generally don't like to have packages fail just because the conditions for running aren't met. "Fail" can mean a phone call in the middle of the night. If this is something that needs to be addressed immediately, that's fine, but if it's not, I'd suggest a graceful exit instead.
A first thought would be to add another Execute SQL task in front of the one you have. In that task, execute the query you're using, but just return a row count, then pass that count to a variable. Then have two precedent constraints coming away from the new Execute SQL task.
Connect your first constraint to your existing Execute SQL task, but add a condition that your row count variable has to be >0.
Create another constraint with the condition that row count ==0. Connect that to, for instance, a Send Mail task that will generate an email saying there were no rows to process, and let the package execution end there.
To have your package fail when there are no rows in the object variable, add an OnPostExecute Event Handler to the Execute SQL Task before the Foreach Loop. In this Event Handler, create a Script Task that checks for existing rows in the object variable, then raises an error if none are found. A DataTable object can be used as outlined below for this, and of course you can include whatever information in the error message that you need. On the Script Task, the FailPackageOnFailure property will need to be set to true.
Although raising the error will already fail the package this prevents subsequent tasks from being executed. The following outlines this further and a reference to the System.Data.OleDb namespace is necessary for this example.
OleDbDataAdapter od = new OleDbDataAdapter();
System.Data.DataTable dt = new System.Data.DataTable();
od.Fill(dt, Dts.Variables["User::YourObjectVariable"].Value);
if (dt.Rows.Count > 0)
{
//If no processing is necessary, nothing needs to be done here.
}
else
{
Dts.Events.FireError(0, "Error", "No rows were available.", String.Empty, 0);
}

Stored procedure why return statement in SQL Server?

General procedure are no return value then stored procedure why return?
As you wrote, stored procedure do not return any value. They run from its beginning to its end and, when no more statements to execute, they get back to the invoking code.
The use of a RETURN statement within a stored procedure is when you don't want to continue its processing. Example:
You have a stored procedure that receives 3 parameters and returns 2, a result and a status code (e.g. SUCCESS or FAIL). The procedure first checks that all the received parameters are present and within legal values and, if not present or illegal values are found, you don't want to proceed and simply RETURN to the invoking code with the applicable status code. You do this through the RETURN command.
Hope this is clear.
I'm not sure what is your problem. You mean why SP need a return statement?
Because in some case, we need process cross table operation and complex calculation. If we need a result we should return a result from SP.
In some aggregate calculation we need a final result, but the aggregate SQL is very complex. So we need use the SP instead of general SQL statement then return a result.

Wrong error in SSIS - [Execute SQL Task] Error: There is an invalid number of result bindings returned for the ResultSetType: "ResultSetType_Rowset"

I have an Execute SQL task which gives returns only one row with one column - a number. I set my result set to single row. Despite that, the task fails. Why ? How do I fix it ?
[Execute SQL Task] Error: There is an invalid number of result bindings returned for the
ResultSetType: "ResultSetType_Rowset".
Probably, you haven't configured your resultset parametrs correctly. To configure it, click on ResultSet in the Execute SQL Task, click Add. In the 'ResultSetName' column, enter the exact name of the columnname that you are retrieving or simply give it 0. In the 'variablename', select the variable you created to map the data returned.
In my case the ResultSet configured to "Full result set" when there were no results being returned. The Stored Procedure I was calling was simply deleting data. So I sat this to "None" and it worked..
Old question (but Google still finds it :-))
If you want to use a rowset as result (usually to combine it with an ForEach-Loop)
you have to create a variable with the type "Object" (e.g. MyResultSet)
in the Execute SQL task the ResultSet property must be Full Rowset (is already, when you are receiving the error message above)
on the ResultSet pane (left list entry) you have to add a single entry, set it name to 0 and its variable to the Object type variable (MyResultSet)
in the ForEachLoop-Container you have to switch to the Collation pane (left list entry)
there set the Enumerator property to Foreach-ADO-Enumerator
the (now visible) ADO-ObjectSourceVariable has to be set to your Object variable (User:MyResultSet)
Click onto the Variable assignment entry in the left pane
create an entry for every column in the result set (and hope you did not use a select * for a 100 column table :-))

Problem With Parameter Multiplied By Negative Value In Where Clause in OLE DB Source

I've this query in my OLE DB Source, using a parameter inside it:
select *
from A
where A.A_DATE >= DATEADD(d,-1*(CAST(? as int)),GETDATE())
with parameter X used. For sample case, I use X = 1. If I run the above query in the SQL Server Management Studio, it returns a row (the correct one). But when I run it inside the SSIS package it doesn't return any row (which is incorrect). When remove the -1*xxx and go straight with the CAST(? as int) (the query looks like this:)
select *
from A
where A.A_DATE >= DATEADD(d,CAST(? as int),GETDATE())
and set the X value to -1, it shows the correct result (a row returned). Is there something wrong with the parameter multiplication with a negative value inside an OLE DB Source query?
update 1:
It seems there is another problem with the 2nd query, as if I change the value to 1, I still get row results (when it shouldn't). Any solutions??
update 2:
it seems the cast solution is used is also flawed, since it doesn't return the correct value either. I kept getting 2 rows returned when I should have only 1 row returned
Seems the query above is also flawed in SSIS, so I decided to use this query, so I don't have to use CAST:
"select *
from A
where A.A_DATE >= DATEADD(d," + #[User::Y] + ",GETDATE())"
and put it inside a variable (let's called it Src_Query) and then evaluate the string above as an Expression. I also used variable Y with String data type instead of X with data type Int32 I used previously, and to turn it to negative value I just used Script Task to deal with it. Then in the OLE DB Source I used the "SQL Command from variable" option. I run the package, and the query returned the correct result. It's also useful for variable that I used inside sub-queries.
The problem with the above solution: In my project I have some source query that has more than 4000 chars, and SSIS doesn't allow more than 4000 chars processed in the Expression Builder. Still searching a way to go around this problem.
Update 1: I've workaround my problem for more than 4000 chars-long query, by putting the where clause in a separate Conditional Split after the data retrieval, and I still can use my Int32-typed variable.
This is the expression that the conditional split used, with the query in OLE DB Source no longer has the where clause related to the date:
A_DATE >= DATEADD("d",#[User::X],(DT_DBDATE)GETDATE())
Wonder how it will affect the performance though, is it significant?

Resources