Can't get data to flow correctly in SSIS - ssis

I'm having some issues getting my data flow to do what I want it to.
I'm using an OLEDB Source that calls a stored procedure that uses a table variable to show me the data that I need to use.
It looks like this:
ClientID TimeStamp IsStart
pic#psdfj 2013-08-28 14:22:59 1
bsd#fjskk 2013-08-28 14:43:21 1
pic#psdfj 2013-08-28 15:23:01 0
..and so on
I need to create two new columns, one with the timestamp, and the other with the IsStart column addded up. (I'm keeping track of when users are online and capturing the timestamp.)
So I have a currently empty table in my SQL Server db called tblUserUsage, with the columns:
tblUserUsage (example of what the data would look like)
TimeStamp NumberOfUsers
2013-08-28 14:22:59 1
2013-08-28 14:43:21 2
2013-08-28 15:23:01 1
I'm having issues getting my data flow to output to those columns. Right now I have the storedprocedure call connected to a Derived Column, then to a script. But that isn't working as it's not letting me output to the outputbuffer in the script when I create output columns. Just for clarification - the script will be in VB.NET
This is what my script looks like so far. I have a NumberOfUsers column added to the output. But I still have no Output0buffer
Anyone have any ideas?

You only get an OutputBuffer generated in your code for asynchronous transforms (where the SynchronousInputID property of one or more outputs is set to zero). For synchronous transforms, your output columns will be in the InputBuffer.
Compare the MSDN articles Creating an Asynchronous Transformation with the Script Component and Creating a Synchronous Transformation with the Script Component.

Did you add a column to your output like this?
Then your output buffer would look something like this:
TableOutputBuffer.OutputColumnName = "hello";
Take a look a this sample I found here and maybe compare it to your code.. I usually write my scripts in c# so I can tell you if you're missing anything off the top of my head, but it might be worth a try.
Public Class ScriptMain
Inherits UserComponent
Dim connMgr As IDTSConnectionManager100
Dim sqlConn As SqlConnection
Dim sqlReader As SqlDataReader
Public Overrides Sub AcquireConnections(ByVal Transaction As Object)
connMgr = Me.Connections.MyADONETConnection
sqlConn = CType(connMgr.AcquireConnection(Nothing), SqlConnection)
End Sub
Public Overrides Sub PreExecute()
Dim cmd As New SqlCommand("SELECT AddressID, City, StateProvinceID FROM Person.Address", sqlConn)
sqlReader = cmd.ExecuteReader
End Sub
Public Overrides Sub CreateNewOutputRows()
Do While sqlReader.Read
With MyAddressOutputBuffer
.AddRow()
.AddressID = sqlReader.GetInt32(0)
.City = sqlReader.GetString(1)
End With
Loop
End Sub
Public Overrides Sub PostExecute()
sqlReader.Close()
End Sub
Public Overrides Sub ReleaseConnections()
connMgr.ReleaseConnection(sqlConn)
End Sub
End Class

Related

Copy a DataRow to another table (vb.net / mysql)

I have a Two identical data tables in my project, One is Purchase Orders and the other is a template datatable. (IE: the user can select a template when creating a new row in the original table.)
A Save Template button runs:
Public Shared Sub AddPO_as_Template(Name As String, DR As DataRow)
Dim ds As New SomeDataSet
Dim ta As New SomeDataSetDataSetTableAdapters.PurchaseOrderTemplatesTableAdapter
Try
DR("Name") = Name
ds.PurchaseOrderTemplates.ImportRow(DR)
ta.Update(ds)
Catch ex As Exception
CommonRoutines.ShowExceptionDialog("Could not add the Template, an error occured.", ex.Message)
End Try
End Sub
This particular code throws a concurrency violation. I assume this is happening because the ID column is auto increment and I as using the origional row's ID.
Now; the ID in the second table (PurchaseOrderTemplates) is not important at all, so it can be anything. I have tried setting -1, dbnull, "", etc.... the DB keeps trowing exceptions on the update command.
How can I reset the ID column so it just adds as normal? (I know i could create a newrow and move all the columns accross, but this seems the long way.)
Thanks
EDIT: Copying the rows (via .itemarray) works fine, but i need to get the auto increment value from the table somehow to avoid concurrency violations.
Edit2: So i got it working as per the answer below, but I'd still love to know how to get import row working like this.
Adding the Row as follows works.
Public Shared Sub AddPO_as_Template(Name As String, DR As DataRow)
Dim ds As New SomeDataSet
Dim ta As New SomeDataSetTableAdapters.PurchaseOrderTemplatesTableAdapter
Dim NewRow As DataRow
NewRow = ds.PurchaseOrderTemplates.NewRow
NewRow.ItemArray = DR.ItemArray
NewRow("Name") = Name
NewRow("ID") = 1
ds.PurchaseOrderTemplates.Rows.Add(NewRow)
ta.Update(ds)
End Sub
The MySQL database ignores the value in the ID column, and just sets its own auto increment value.

Grab data from Mysql and loop through results

I need to check a mysql table periodically and if there are any rows found, I need to loop through them and perform some actions.
My SQL string is nice and simple: "SELECT * FROM 'dbcpman_jobs'".
There could be 1 returned row, or there could be 20 returned rows.
For each returned row, I need to assign some of the data to variables...
Dim job_id As String = jobrow.Item("id")
Dim job_jobid As String = jobrow.Item("jobid")
Dim job_status As String = jobrow.Item("status")
Dim job_dbxid As String = jobrow.Item("dbxid")
Then i need to make an API call using the information that's just been split out...
Try
Dim jobapicall As New System.Net.WebClient
jobcheckresult = jobapicall.DownloadString(fulljobapicheckurl)
Catch ex As Exception
Console.WriteLine("Error 'DBX-Err-1' - Error during API call")
End Try
Can someone point me in the right direction to loop through all rows found?
My code currently checks the first item found only, which is not ideal as if that job fails, everything else gets held up.
Thanks
FOR EACH loop was the answer.
something like this...
For Each jobRow As DataRow in dtJobResults.Rows
Try
what I want to do for each returned row.
Catch Ex as exception
messagebox.show("Oh no, something went wrong!")
End Try
Next

SSIS Convert Blank or other values to Zeros

After applying the unpivot procedure, I have an Amount column that has blanks and other characters ( like "-"). I would like to convert those non-numberic values to zero. I use replace procedure but it only converts one at the time.
Also, I tried to use the following script
/**
Public Overrides Sub Input()_ProcessInputRows(ByVal Row As Input()Buffer)
If Row.ColumnName_IsNull = False Or Row.ColumnName = "" Then
Dim pattern As String = String.Empty
Dim r As Regex = Nothing
pattern = "[^0-9]"
r = New Regex(pattern, RegexOptions.Compiled)
Row.ColumnName = Regex.Replace(Row.ColumnName, pattern, "")
End If
End Sub
**/
but i'm getting error.I don't much about script so maybe I placed in the wrong place. The bottom line is that I need to convert those non-numberic values.
Thank you in advance for your help.
I generally look at regular expressions as a great way to introduce another problem into an existing one.
What I did to simulate your problem was to write a select statement that added 5 rows. 2 with valid numbers, the rest were an empty string, string with spaces and one with a hyphen.
I then wired it up to a Script Component and set the column as read/write
The script I used is as follows. I verified there was a value there and if so, I attempted to convert the value to an integer. If that failed, then I assigned it zero. VB is not my strong suit so if this could have been done more elegantly, please edit my script.
Public Overrides Sub Input0_ProcessInputRow(ByVal Row As Input0Buffer)
' Ensure we have data to work with
If Not Row.ColumnName_IsNull Then
' Test whether it's a number or not
' TryCast doesn't work with value types so I'm going the lazy route
Try
' Cast to an integer and then back to string because
' my vb is weak
Row.ColumnName = CStr(CType(Row.ColumnName, Integer))
Catch ex As Exception
Row.ColumnName = 0
End Try
End If
End Sub

How to do a simple entity copy in Linq-to-SQL?

When using a Linq-to-SQL class, how can I make a simple copy of an entity and save it?
My entity has a guid for a unique ID that gets automatically generated in the SQL Server.
I don't require a "deep clone".
I tried to use some clone methods that are out there but I couldn't figure out how to get everything serialized that needed to be serialized (got stuck on the DataContext not being serializable).
Can I just get an entity, detach it from the DataContext, null out the unique ID and InsertOnSubmit in a new DataContext? If so, how would I do this?
VB.net code preferred but not required.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
UPDATE:
Public Shared Function ReIssue(RequestID As Guid) As Guid
Dim req As Request
Dim new_req As Request
Using dc1 As New MBDataContext()
req = (From r In dc1.Requests Where r.ID = RequestID).Single()
End Using
new_req = req
new_req.ID = Guid.Empty
new_req.CreateDate = Nothing
Using dc2 As New MBDataContext()
dc2.Requests.InsertOnSubmit(new_req)
dc2.SubmitChanges()
End Using
End Function
I get an error: An attempt has been made to Attach or Add an entity that is not new, perhaps having been loaded from another DataContext. This is not supported.
on this line: dc2.Requests.InsertOnSubmit(new_req)
Nulling out the unique id and then calling InsertOnSubmit is the right way to go. Some things you have to consider though:
What is the type of the id? Is it an int? A Guid? Is it nullable? If it is nullable, make sure to set it to null, if it is an int, then to 0, or a Guid, then to Guid.Empty.
Does the type have a timestamp of some kind? If so, then you have to reset/set it to null as well, depending on the type.
Once you've done that, you can call InsertOnSubmit and then SubmitChanges and the change should take place.
Note, if you are doing this for a large number of records, you are better off writing a stored procedure which will perform the insert into the table using a select from the other table. It will be much faster that way (you won't be loading the data from the database into memory then pushing it back, inserting the records one at a time).
This method seems to have worked perfectly.
Making the final code look like this:
Public Shared Function ReIssue(RequestID As Guid) As Guid
Using dc As New MBDataContext()
Dim req As Request
req = (From r In dc.Requests Where r.ID = RequestID).Single()
Dim new_req As Request = DirectCast(Entity.Copy(req, New Request()), Request)
dc.Requests.InsertOnSubmit(new_req)
dc.SubmitChanges()
req.ActiveRequestParentID = new_req.ID
dc.SubmitChanges()
Return new_req.ID
End Using
End Function
Public NotInheritable Class Entity
Private Sub New()
End Sub
Public Shared Function Copy(source As Object, destination As Object) As Object
Dim sourceProps As System.Reflection.PropertyInfo() = source.[GetType]().GetProperties()
Dim destinationProps As System.Reflection.PropertyInfo() = destination.[GetType]().GetProperties()
For Each sourceProp As System.Reflection.PropertyInfo In sourceProps
Dim column As ColumnAttribute = TryCast(Attribute.GetCustomAttribute(sourceProp, GetType(ColumnAttribute)), ColumnAttribute)
If column IsNot Nothing AndAlso Not column.IsPrimaryKey Then
For Each destinationProp As System.Reflection.PropertyInfo In destinationProps
If sourceProp.Name = destinationProp.Name AndAlso destinationProp.CanWrite Then
destinationProp.SetValue(destination, sourceProp.GetValue(source, Nothing), Nothing)
Exit For
End If
Next
End If
Next
Return destination
End Function
End Class

LinQ Query help

I have added a table(ViolationsDataSourceConfig) to the dbml file.
The context name is ViolationsDataContext.
I am trying to write a function that should return employee object but it is throwing errors. Below is the code. Is there any easy way for achieving this. I just want the ViolationsDataSourceConfig.
Public Shared Function GetDataSourceDetails(ByVal ApplicationID As Integer) As ViolationsDataSourceConfig
Dim _db As New ViolationsDataContext
Dim appSource As New ViolationsDataSourceConfig
Dim application As Table(Of ViolationsDataSourceConfig) = _db.GetTable(Of ViolationsDataSourceConfig)()
Try
appSource = From a In application Where a.ApplicationID = ApplicationID And a.Status = 1 _
Select a
Catch ex As Exception
End Try
Return appSource
End Function
It's a little hard without more information regarding your data structures or the errors you're getting, could you provide the error at least?
Also, you say your LINQ statement should "return employee" but you are typing it as "ViolationsDataSourceConfig", how does that work?
My first thought would be the LINQ statement will return an IEnumerable by default so it probably won't be the correct type.
ppSource = (From a In application Where a.ApplicationID = ApplicationID And a.Status = 1 _
Select a).FirstOrDefault()
Might be closer to your goal...