Showing posts with label input. Show all posts
Showing posts with label input. Show all posts

Sunday, March 11, 2012

Create output columns based on input in custom component

I'm trying to create a fairly simple custom transform component (because I've read that's the easiest one to create) which will take one column from a flat file source and based on the first row create the output columns.

I'm actually trying to write a component that will solve the now well known problem with parsing CSV files in SSIS. I have a lot of source files and all have many columns so a component that can read in the first line from the CSV file and create the output columns automatically will save me lots of time when migrating the old DTS packages.

I have the basic component set up but I'm stuck when trying to override the OnInputPathAttached method because I don't know how to use the inputID to get the first line from the input (the buffer).

Are there any good examples for creating output columns dynamically based on the input buffer?

Should I just give up on on the transform and create a custom source component instead?

Since there aren't any rows in the buffer until runtime, I don't see how this will work. Packages can't change their metadata (inputs / outputs) at runtime. You could write a source that uses the connection manager at design time to read the first line from the file, and add the output columns, but that would be by directly reading the flat file, not by using a row from the buffer.|||

You could try something like this-

IDTSInput90 input = ComponentMetaData.InputCollection[inputID];

This is a design-time action, in the same way as you would "normally" use the flat file source to load a CSV file, and let the designer UI figure out the columns. This will not allow you to change the file layout at run-time, and magically load any file you happen to find. You area aware of this distinction?

From a design pattern perspective, this is not the place to be selecting and generating columns. It would be more sensible to do this either in a UI or ReinitializeMetadata. Validate could detect the stupid state of no input columns selected, and/or it not matching the input, and call RMD.

A source may be cleaner, or even a package generator. I am not clear on what you are really trying to do, and what problem you need to solve.

|||

Thanks,

I'm trying to solve the problem related to a CSV source missing columns for some rows, it's been brought up a few times here in the past but I haven't seen a generic solution that is suitable for multiple DTS packages that are dependent on multiple CSV files all with 50+ columns.

Here's a forum entry on it:

http://forums.microsoft.com/TechNet/ShowPost.aspx?PostID=2025483&SiteID=17

And Jamie T's explanation with more links:

http://blogs.conchango.com/jamiethomson/archive/2007/05/15/SSIS_3A00_--Flat-File-Connection-Manager-issues.aspx

I'll see if I can get the custom source component working today.

|||

I was able to get the source component working based off an example from Professional SQL Server 2005 Integration Services

http://www.wrox.com/WileyCDA/WroxTitle/productCd-0764584359.html

(The site has a page for downloading the examples).

The example for creating a source component had a couple errors in it (probably from being based off a pre-release version of SSIS).

Here's some of the key code:

Code Snippet

public override void AcquireConnections(object transaction)

{

if (ComponentMetaData.RuntimeConnectionCollection["File To Read"].ConnectionManager != null)

{

ConnectionManager cm = Microsoft.SqlServer.Dts.Runtime.DtsConvert.ToConnectionManager(ComponentMetaData.RuntimeConnectionCollection["File To Read"].ConnectionManager);

if (cm.CreationName != "FLATFILE")

{

throw new Exception("The Connection Manager is not a FILE Connection Manager");

}

else

{

_fileExist = (Microsoft.SqlServer.Dts.Runtime.DTSFileConnectionUsageType)cm.Properties["FileUsageType"].GetValue(cm);

if (_fileExist != Microsoft.SqlServer.Dts.Runtime.DTSFileConnectionUsageType.FileExists)

{

throw new Exception("The type of FILE connection manager must be an Existing File");

}

else

{

_filename = ComponentMetaData.RuntimeConnectionCollection["File To Read"].ConnectionManager.AcquireConnection(transaction).ToString();

if (_filename == null || _filename.Length == 0)

{

throw new Exception("Nothing returned when grabbing the filename");

}

}

}

}

}

The original example checked "if (cm.CreationName != "FILE")" which should actually be "if (cm.CreationName != "FLATFILE")"

Code Snippet

private void CreateOutputAndMetaDataColumns(IDTSOutput90 output)

{

if (_filename != null || _filename.Length > 0)

{

TextReader tr = File.OpenText(_filename);

string columns = tr.ReadLine();

tr.Close();

_columnNames = columns.Split(",".ToCharArray());

foreach (string columnName in _columnNames)

{

IDTSOutputColumn90 outName = output.OutputColumnCollection.New();

outName.Name = columnName.Trim();

outName.Description = columnName.Trim();

outName.SetDataTypeProperties(DataType.DT_STR, 50, 0, 0, 1252);

//Create an external metadata column to go alongside with it

CreateExternalMetaDataColumn(output.ExternalMetadataColumnCollection, outName);

}

}

}

Just to get the sample working all columns are strings for the moment, for my needs this is all I needed anyways.

Code Snippet

private bool DoesEachOutputColumnHaveAMetaDataColumnAndDoDatatypesMatch(int outputID)

{

IDTSOutput90 output = ComponentMetaData.OutputCollection.GetObjectByID(outputID);

IDTSExternalMetadataColumn90 mdc;

bool rtnVal = true;

int cCount = 0;

foreach (IDTSOutputColumn90 col in output.OutputColumnCollection)

{

if (col.ExternalMetadataColumnID == 0)

{

rtnVal = false;

}

else

{

//mdc = output.ExternalMetadataColumnCollection[col.ExternalMetadataColumnID];

mdc = output.ExternalMetadataColumnCollection[cCount];

if (mdc.DataType != col.DataType || mdc.Length != col.Length || mdc.Precision != col.Precision

|| mdc.Scale != col.Scale || mdc.CodePage != col.CodePage)

{

rtnVal = false;

}

cCount++;

}

}

return rtnVal;

}

This was the other change I needed to make to the example, the collection index doesn't match the column ID.

I'll try to post the full source code online if I get some time so that hopefully it saves someone else the trouble.

Create output columns based on input in custom component

I'm trying to create a fairly simple custom transform component (because I've read that's the easiest one to create) which will take one column from a flat file source and based on the first row create the output columns.

I'm actually trying to write a component that will solve the now well known problem with parsing CSV files in SSIS. I have a lot of source files and all have many columns so a component that can read in the first line from the CSV file and create the output columns automatically will save me lots of time when migrating the old DTS packages.

I have the basic component set up but I'm stuck when trying to override the OnInputPathAttached method because I don't know how to use the inputID to get the first line from the input (the buffer).

Are there any good examples for creating output columns dynamically based on the input buffer?

Should I just give up on on the transform and create a custom source component instead?

Since there aren't any rows in the buffer until runtime, I don't see how this will work. Packages can't change their metadata (inputs / outputs) at runtime. You could write a source that uses the connection manager at design time to read the first line from the file, and add the output columns, but that would be by directly reading the flat file, not by using a row from the buffer.|||

You could try something like this-

IDTSInput90 input = ComponentMetaData.InputCollection[inputID];

This is a design-time action, in the same way as you would "normally" use the flat file source to load a CSV file, and let the designer UI figure out the columns. This will not allow you to change the file layout at run-time, and magically load any file you happen to find. You area aware of this distinction?

From a design pattern perspective, this is not the place to be selecting and generating columns. It would be more sensible to do this either in a UI or ReinitializeMetadata. Validate could detect the stupid state of no input columns selected, and/or it not matching the input, and call RMD.

A source may be cleaner, or even a package generator. I am not clear on what you are really trying to do, and what problem you need to solve.

|||

Thanks,

I'm trying to solve the problem related to a CSV source missing columns for some rows, it's been brought up a few times here in the past but I haven't seen a generic solution that is suitable for multiple DTS packages that are dependent on multiple CSV files all with 50+ columns.

Here's a forum entry on it:

http://forums.microsoft.com/TechNet/ShowPost.aspx?PostID=2025483&SiteID=17

And Jamie T's explanation with more links:

http://blogs.conchango.com/jamiethomson/archive/2007/05/15/SSIS_3A00_--Flat-File-Connection-Manager-issues.aspx

I'll see if I can get the custom source component working today.

|||

I was able to get the source component working based off an example from Professional SQL Server 2005 Integration Services

http://www.wrox.com/WileyCDA/WroxTitle/productCd-0764584359.html

(The site has a page for downloading the examples).

The example for creating a source component had a couple errors in it (probably from being based off a pre-release version of SSIS).

Here's some of the key code:

Code Snippet

public override void AcquireConnections(object transaction)

{

if (ComponentMetaData.RuntimeConnectionCollection["File To Read"].ConnectionManager != null)

{

ConnectionManager cm = Microsoft.SqlServer.Dts.Runtime.DtsConvert.ToConnectionManager(ComponentMetaData.RuntimeConnectionCollection["File To Read"].ConnectionManager);

if (cm.CreationName != "FLATFILE")

{

throw new Exception("The Connection Manager is not a FILE Connection Manager");

}

else

{

_fileExist = (Microsoft.SqlServer.Dts.Runtime.DTSFileConnectionUsageType)cm.Properties["FileUsageType"].GetValue(cm);

if (_fileExist != Microsoft.SqlServer.Dts.Runtime.DTSFileConnectionUsageType.FileExists)

{

throw new Exception("The type of FILE connection manager must be an Existing File");

}

else

{

_filename = ComponentMetaData.RuntimeConnectionCollection["File To Read"].ConnectionManager.AcquireConnection(transaction).ToString();

if (_filename == null || _filename.Length == 0)

{

throw new Exception("Nothing returned when grabbing the filename");

}

}

}

}

}

The original example checked "if (cm.CreationName != "FILE")" which should actually be "if (cm.CreationName != "FLATFILE")"

Code Snippet

private void CreateOutputAndMetaDataColumns(IDTSOutput90 output)

{

if (_filename != null || _filename.Length > 0)

{

TextReader tr = File.OpenText(_filename);

string columns = tr.ReadLine();

tr.Close();

_columnNames = columns.Split(",".ToCharArray());

foreach (string columnName in _columnNames)

{

IDTSOutputColumn90 outName = output.OutputColumnCollection.New();

outName.Name = columnName.Trim();

outName.Description = columnName.Trim();

outName.SetDataTypeProperties(DataType.DT_STR, 50, 0, 0, 1252);

//Create an external metadata column to go alongside with it

CreateExternalMetaDataColumn(output.ExternalMetadataColumnCollection, outName);

}

}

}

Just to get the sample working all columns are strings for the moment, for my needs this is all I needed anyways.

Code Snippet

private bool DoesEachOutputColumnHaveAMetaDataColumnAndDoDatatypesMatch(int outputID)

{

IDTSOutput90 output = ComponentMetaData.OutputCollection.GetObjectByID(outputID);

IDTSExternalMetadataColumn90 mdc;

bool rtnVal = true;

int cCount = 0;

foreach (IDTSOutputColumn90 col in output.OutputColumnCollection)

{

if (col.ExternalMetadataColumnID == 0)

{

rtnVal = false;

}

else

{

//mdc = output.ExternalMetadataColumnCollection[col.ExternalMetadataColumnID];

mdc = output.ExternalMetadataColumnCollection[cCount];

if (mdc.DataType != col.DataType || mdc.Length != col.Length || mdc.Precision != col.Precision

|| mdc.Scale != col.Scale || mdc.CodePage != col.CodePage)

{

rtnVal = false;

}

cCount++;

}

}

return rtnVal;

}

This was the other change I needed to make to the example, the collection index doesn't match the column ID.

I'll try to post the full source code online if I get some time so that hopefully it saves someone else the trouble.

Create output columns based on input in custom component

I'm trying to create a fairly simple custom transform component (because I've read that's the easiest one to create) which will take one column from a flat file source and based on the first row create the output columns.

I'm actually trying to write a component that will solve the now well known problem with parsing CSV files in SSIS. I have a lot of source files and all have many columns so a component that can read in the first line from the CSV file and create the output columns automatically will save me lots of time when migrating the old DTS packages.

I have the basic component set up but I'm stuck when trying to override the OnInputPathAttached method because I don't know how to use the inputID to get the first line from the input (the buffer).

Are there any good examples for creating output columns dynamically based on the input buffer?

Should I just give up on on the transform and create a custom source component instead?

Since there aren't any rows in the buffer until runtime, I don't see how this will work. Packages can't change their metadata (inputs / outputs) at runtime. You could write a source that uses the connection manager at design time to read the first line from the file, and add the output columns, but that would be by directly reading the flat file, not by using a row from the buffer.|||

You could try something like this-

IDTSInput90 input = ComponentMetaData.InputCollection[inputID];

This is a design-time action, in the same way as you would "normally" use the flat file source to load a CSV file, and let the designer UI figure out the columns. This will not allow you to change the file layout at run-time, and magically load any file you happen to find. You area aware of this distinction?

From a design pattern perspective, this is not the place to be selecting and generating columns. It would be more sensible to do this either in a UI or ReinitializeMetadata. Validate could detect the stupid state of no input columns selected, and/or it not matching the input, and call RMD.

A source may be cleaner, or even a package generator. I am not clear on what you are really trying to do, and what problem you need to solve.

|||

Thanks,

I'm trying to solve the problem related to a CSV source missing columns for some rows, it's been brought up a few times here in the past but I haven't seen a generic solution that is suitable for multiple DTS packages that are dependent on multiple CSV files all with 50+ columns.

Here's a forum entry on it:

http://forums.microsoft.com/TechNet/ShowPost.aspx?PostID=2025483&SiteID=17

And Jamie T's explanation with more links:

http://blogs.conchango.com/jamiethomson/archive/2007/05/15/SSIS_3A00_--Flat-File-Connection-Manager-issues.aspx

I'll see if I can get the custom source component working today.

|||

I was able to get the source component working based off an example from Professional SQL Server 2005 Integration Services

http://www.wrox.com/WileyCDA/WroxTitle/productCd-0764584359.html

(The site has a page for downloading the examples).

The example for creating a source component had a couple errors in it (probably from being based off a pre-release version of SSIS).

Here's some of the key code:

Code Snippet

public override void AcquireConnections(object transaction)

{

if (ComponentMetaData.RuntimeConnectionCollection["File To Read"].ConnectionManager != null)

{

ConnectionManager cm = Microsoft.SqlServer.Dts.Runtime.DtsConvert.ToConnectionManager(ComponentMetaData.RuntimeConnectionCollection["File To Read"].ConnectionManager);

if (cm.CreationName != "FLATFILE")

{

throw new Exception("The Connection Manager is not a FILE Connection Manager");

}

else

{

_fileExist = (Microsoft.SqlServer.Dts.Runtime.DTSFileConnectionUsageType)cm.Properties["FileUsageType"].GetValue(cm);

if (_fileExist != Microsoft.SqlServer.Dts.Runtime.DTSFileConnectionUsageType.FileExists)

{

throw new Exception("The type of FILE connection manager must be an Existing File");

}

else

{

_filename = ComponentMetaData.RuntimeConnectionCollection["File To Read"].ConnectionManager.AcquireConnection(transaction).ToString();

if (_filename == null || _filename.Length == 0)

{

throw new Exception("Nothing returned when grabbing the filename");

}

}

}

}

}

The original example checked "if (cm.CreationName != "FILE")" which should actually be "if (cm.CreationName != "FLATFILE")"

Code Snippet

private void CreateOutputAndMetaDataColumns(IDTSOutput90 output)

{

if (_filename != null || _filename.Length > 0)

{

TextReader tr = File.OpenText(_filename);

string columns = tr.ReadLine();

tr.Close();

_columnNames = columns.Split(",".ToCharArray());

foreach (string columnName in _columnNames)

{

IDTSOutputColumn90 outName = output.OutputColumnCollection.New();

outName.Name = columnName.Trim();

outName.Description = columnName.Trim();

outName.SetDataTypeProperties(DataType.DT_STR, 50, 0, 0, 1252);

//Create an external metadata column to go alongside with it

CreateExternalMetaDataColumn(output.ExternalMetadataColumnCollection, outName);

}

}

}

Just to get the sample working all columns are strings for the moment, for my needs this is all I needed anyways.

Code Snippet

private bool DoesEachOutputColumnHaveAMetaDataColumnAndDoDatatypesMatch(int outputID)

{

IDTSOutput90 output = ComponentMetaData.OutputCollection.GetObjectByID(outputID);

IDTSExternalMetadataColumn90 mdc;

bool rtnVal = true;

int cCount = 0;

foreach (IDTSOutputColumn90 col in output.OutputColumnCollection)

{

if (col.ExternalMetadataColumnID == 0)

{

rtnVal = false;

}

else

{

//mdc = output.ExternalMetadataColumnCollection[col.ExternalMetadataColumnID];

mdc = output.ExternalMetadataColumnCollection[cCount];

if (mdc.DataType != col.DataType || mdc.Length != col.Length || mdc.Precision != col.Precision

|| mdc.Scale != col.Scale || mdc.CodePage != col.CodePage)

{

rtnVal = false;

}

cCount++;

}

}

return rtnVal;

}

This was the other change I needed to make to the example, the collection index doesn't match the column ID.

I'll try to post the full source code online if I get some time so that hopefully it saves someone else the trouble.

Sunday, February 19, 2012

Create Dynamic Report

Mr. Babu,

How can I manipulate the query from VB depending on the input entered by the user. In this case I can make one report only and modify the query and pass it to the report.
Otherwise for each user input I will have call a different report.
If possible do send me an example.

Thanks,

SatishHave you try to pass parameters to your report?|||I have tried parameters and it works, but I would like to chang the sql
i.e. select * from .... where empno= variable

regards,
Satish|||This may be more trouble than it's worth...

You could change your report so that VB does all the database queries and passes a recordset to your report.

Example 1:

Dim CrApp1 As New CRPEAuto.Application
Dim CrRep As CRPEAuto.Report
Dim CrDB As CRPEAuto.Database
Dim CrTables As CRPEAuto.DatabaseTables
Dim CrTable As CRPEAuto.DatabaseTable

'open report
Set CrRep = CrApp1.OpenReport("C:\Report.rpt")

'set the database object to the reports database
Set CrDB = CrRep.Database

'Set the databasetables object
Set CrTables = CrDB.Tables

'set the databasetable object to the first table in the report
Set CrTable = CrTables(1)

'sets ADO recordset as the data for the first table
CrTable.SetPrivateData 3, rsData

'preview the report with the ADO recordset as the data
CrRep.Preview

Example 2 (uses RDC, which I like better):

Dim Report As New CrystalReport1

Report.Database.SetDataSource rsData, 3, 1

CRViewer1.ReportSource = Report
CRViewer1.ViewReport

In Example 2, CrystalReport1 is the dsr file created by clicking 'Project', 'Add Crystal Report 8.5' in the VB IDE. CRViewer1 is the Crystal Report Viewer component.

Both of these examples were created using CR 8.5 and VB 6.|||This is in reference to your reply.

In Example 2, CrystalReport1 is the dsr file created by clicking 'Project', 'Add Crystal Report 8.5' in the VB IDE.

When I click Project, I cannot see "Add Crystal Report 8.5".
How do I get it.

Regards,
Satish|||I am not getting CRPEAuto method. What reference has to be made.

what does crpeauto stand for?|||My References for the 'CRPEAuto' Method says 'Crystal Report Engine 8 Object Library'

As for the 'Add Crystal Report 8.5', do you have Crystal Reports Developer Edition installed on your development machine? If so, what version? I think RDC was made avaiable in either version 8 or 8.5 and higher.

You can try to do a search on Crystal's website:
http://support.businessobjects.com/search/advsearch.asp|||how do I get the reference to "'Crystal Report Engine 8 Object Library'" in my computer.|||I'm using version 8.5 Developer Edition. When I installed it, it placed all the necessary dlls on my comuter for me.

Click 'Project', 'References', and check 'Crystal Report Engine 8 Object Library'