I have a SAP Crystal Report in which maximum records I get from database will be 12. The number of records can vary from 0 to 12 depends on the conditions. Now I need to display fixed 12 rows in my Crystal Report regardless of the number of records retrieved from database.
I suggest you to add new rows to your query results or to your DataTable, But as you want, I can suggest you a dirty way -That I don't test it yet-:
As you know you can have more than one Detail section by inserting new sections below it, and Crystal Report will name them like a, b and so on.
Now, You can add 11 detail sections after your current Detail section.
After Adding them you have your Detail section with data, and other detail sections that comes below it with an empty row, You can add a rectangle as a border and ... .
In properties of the section you can set a formula in front of Suppress by clicking on formula button, Like this formula -in Crystal Syntax-:
if count({your filed}) < 12 then false else true
Note :
12 is for the second detail section, that will reduced for other sections.
For myself in c# I use something like this (as easiest way):
DataTable dt = new DataTable();
dt = /* query result */;
for (int i = 12; i > dt.Rows.Count; i--)
DataRow dr = dt.NewRow();
If you have the database access.
Create a view with 12 dummy rows and outer join with your table. In this case you will get all 12 rows irrespective of number of rows in data table
Related
I have a file source where the data is not in normalized form with any sort of primary key value or repeating group value. I am using Merge Join to put the multiple rows into one merged row. I need to apply some row numbering so that I have a join between the multiple rows, to get them into the one single row for the merge join.
Here is what the source data looks like:
Data Rows:
MSH|BLAH|||BLAHBLAH15|BLAHZ|||
EVN|MOREBLAH|BLAHBLAH11|BLAHY|||
PID|BLAHXX|BLAHBLAH655|BLAHX|||
PV1|BLAHX2|BLAHBLAH42|BLAHX|||||||||
DG1|1||84|XXXX||A
IN1|1||11400|TEST
IN1|2||20100|TEST2
MSH|BLAH2|BLAHBLAH5|BLAHZ|||
EVN|BLAH6|20220131123100
PID|BLAHGG|BLAH222|BLAHX|||
PV1|PV1|BLAHX2|BLAHBLAH42|BLAHX||||||||20220101|
DG1|1||84|XXXX||A
DG1|2||84|XXXX||A
IN1|1||11600|TEST2
What is consistent is that there is always an MSH line as the header, and everything below it belongs with the MSH line at the top.
So I'm trying to accomplish this by applying a row numbering as below, where it goes from 1,1,1,1 to 2,2,2,2,2 incrementing by one wherever it finds the MSH line, as per below:
Data Rows: Numbering Needed:
MSH|BLAH|||BLAHBLAH15|BLAHZ||| 1
EVN|MOREBLAH|BLAHBLAH11|BLAHY||| 1
PID|BLAHXX|BLAHBLAH655|BLAHX||| 1
PV1|BLAHX2|BLAHBLAH42|BLAHX||||||||| 1
DG1|1||84|XXXX||A 1
IN1|1||11400|TEST 1
IN1|2||20100|TEST2 1
MSH|BLAH2|BLAHBLAH5|BLAHZ||| 2
EVN|BLAH6|20220131123100 2
PV1|PV1|BLAHX2|BLAHBLAH42|BLAHX|||||| 2
DG1|1||84|XXXX||A 2
DG1|2||84|XXXX||A 2
IN1|1||11600|TEST2 2
I can't use a specific row count to reset the number, ie: Every 5 rows increment the row numbering, because it's an inconsistent number of rows each time. In the example above, the first set is 7 rows and the 2nd set is 6 rows. I have to do my incrementing by the presence of the "MSH" row value, and apply the same number on down until it finds the next "MSH". I know that have to use a script task (preferably in C#) to generate this row number since my source is a file. But I just can't seem to find the right logic that will do this, since my data doesn't have a repeating key for each row that I can partition by.
This is what I would do to meet your requirements:
Read entire row in a flat file viewer
Go into a script task (source). I forgot to mention to add the row as read only.
Set up an output for each type.
Go into the code.
Set up a variable outside of main processing (in startup)
int counter = 0;
In main row processing:
string[] details = Row.Split('|');
switch(details[0])
{
case "MSH":
counter++; //increment counter
OutputBufferMSH.AddRow();
OutputBufferMSH.Counter = counter;
OutputBufferMSH.Col1 = details[1];
// Repeat for each detail Column
break;
case "EVN":
OutputBufferEVN.AddRow();
OutputBufferEVN.Counter = counter;
OutputBufferEVN.Col1 = details[1];
// Repeat for each detail Column
break;
//Repeat for each row type
}
I personally would not use this counter approach but actually load the MSH row and return the identity column to replace the counter.
Honestly, I would do the whole thing in a console application instead and use a StreamReader to load the flatfile. Readlines and then use the above logic to push the data into DataTables and use a Bulk Insert to load the data. But the above is the solution to do this in SSIS.
There is a lot to unpack here if you are not familiar with C# or the script task object itself.
I'm adding rows to a spreadsheet using OfficeOpenXml row copy method, Every time I add a row, I set the outlinelevel of the row (olLevel incremented outside of loop below). I'm testing with 12 total rows, attempting to place in two groups of six.
for (int j = 0; j < employeeRecordCount; j++) {
detailRow.Copy(outputSheet.Cells[detailRowStart + j, columnA]);
outputSheet.Row(detailRowStart + j).OutlineLevel = olLevel;
startingRow++;
lastdetailRow++;}
When I open the spreadsheet, all rows are in one group of 12 and the last six rows are grouped but nested within the larger group (the six collapse/expand independently of all 12). If I repeat 6 of the records from my input file, those records are grouped together as 12 and the other 6 are nested.
I know I'm forgetting to set something besides outlinelevel to keep the groups seperate from each other but I cannot figure it out.
Can anyone see what I am missing?
The issue was that every detail row began with a header row. Excel was grouping all the rows on one level and creating another nested level to group rows under the next unique header row.
I edited the code to not apply an outline level to the first detail record (header row) and the rows are no longer nested.
I have a datatable with almost 20 columns in it. in another DT i get only the columns I want. Recently my requirements have changed i.e. Firstly the number of columns in the original DT were constant but now it increases or decreases depending upon the data.
So now, if I statically provide the column names I need in my new DT it isnt of much use to me.
Is there any way in which I can include those columns which may or may not be in the Original Datatable????
For eg: col1|col2|col3|.......col20.
The columns that may bve present or absent fall between col12 and col 16. Is there anyway in which I could make it work????
EDIT:
I want col1,col2,col3 and all columns aftr col12...can I do it???
You can have total number of columns from datatable using
DataTable.Columns.Count
So you will know how many columns are there and you will know which column is in datatable and which is not.
I have a datatable that looks like this (all columns have string datatype)
firstCol secondCol thirdCol
1_str1 1_str2 5,1
2_str1 2_str2 5
3_str1 3_str2
.... .... ....
note that on the thirdCol, some fields are blank.
as for the crystal report, I have used the cross-tab feature
Columns: firstCol
Rows: secondCol
Summarized Fields: thirdCol
The columns and rows are okay. The only problem that I have is the summarized fields.
As far as I have searched, it is only used for numeric data (correct me if I'm wrong).
I even created a sample datatable and bound it on the crystal report. Instead of string, it displays the "numeric" (or you may call it integer, decimal, etc) datatype which is not what I want. Is there any way to display it as a string ?
this is the actual datatable
and this is the crystal report cross-tab output
nevermind the total column and row on the crystal report output. I just want to display "5,1" and "1" on the cross-tab, not the numbers.
Sure, you can display the summarized field as a string. When you created the crosstab, the default summary function is count() which is what you're seeing. Instead, go into your crosstab, select your summarized field, and hit the 'Change Summary' button. Instead of count you can use minimum or maximum (interchangeably, since I'm guessing that you will ever only have on entry for each row/column combination).
Once that change has been made, "5,1" will display for HCC and "5" will display for Legionella on Feb 14, and all other summarized fields will be null.
Using C# 2010 I need to open a word 2010 template, search for a bookmark and insert a table there. Actually it should be a 'three-part-table': one row with two columns, after that multiple rows with five columns and finall three rows as single columns. And it should look as one table without paragraphs or empty lines between.
My experience with word automation is quite limited. I can find examples how to create a table at a bookmark - no problem so far - but how can I add a new table immediately after the one before...
Thanks a lot for any help!!
This should do the trick. You don't need multiple tables in order to have different columns; Word lets you have a single table where the first row has 2 columns, the next 3 rows have 5 columns, and the last 3 rows only have 1 column. (You didn't say how many rows you needed with five columns, so I just went with 3.)
//Be sure to add this reference:
//Project>Add Reference>.NET tab>Microsoft.Office.Interop.Word
//open Word App
Microsoft.Office.Interop.Word.Application msWord = new Microsoft.Office.Interop.Word.Application();
//make it visible or it'll stay running in the background
msWord.Visible = true;
//open a new document based on the Word template.
//You shouldn't open the template directly using msWord.Documents.Open(path) unless you want to edit the template itself.
Microsoft.Office.Interop.Word.Document wordDoc = msWord.Documents.Add(#"c:\MyTemplate.dotx");
//find the bookmark
string bookmarkName = "BookmarkToFind";
if (wordDoc.Bookmarks.Exists(bookmarkName))
{
Microsoft.Office.Interop.Word.Bookmark bk = wordDoc.Bookmarks[bookmarkName];
//set the document's range to immediately after the bookmark.
//If you want to add the table *into* the bookmark, it needs to be done differently.
//This page has a good explanation of the differences between adding to the bookmark's range vs adding after the bookmark's range.
//http://gregmaxey.mvps.org/word_tip_pages/insert_text_at_or_in_bookmark.html
//It's a little more hassle because you have to re-add the bookmark after inserting into it,
//so inserting after the bookmark is usually fine less you're going to be inserting text programmatically at the same bookmark a second time.
Microsoft.Office.Interop.Word.Range rng = wordDoc.Range(bk.Range.End, bk.Range.End);
//create a table with 8 rows and 5 columns into the range.
Microsoft.Office.Interop.Word.Table tbl = wordDoc.Tables.Add(rng, 8, 5);
//set the table's borders.
tbl.Borders.InsideLineStyle = Microsoft.Office.Interop.Word.WdLineStyle.wdLineStyleSingle;
tbl.Borders.OutsideLineStyle = Microsoft.Office.Interop.Word.WdLineStyle.wdLineStyleSingle;
//merge the cells in the first row down to 2 columns (Word's cells start at 1, not at 0).
tbl.Cell(1, 1).Merge(tbl.Cell(1, 3));
//distribute the columns evenly
tbl.Rows[1].Select();
msWord.Selection.Cells.DistributeWidth();
//rows 2-5 already have 5 columns so don't touch them.
//merge rows 6-8 into single-columns rows.
for (int x = 6; x < 9; x++)
{
tbl.Cell(x,1).Merge(tbl.Cell(x,5));
}
//put the cursor in the table's first cell.
rng=wordDoc.Range(tbl.Cell(1,1).Range.Start, tbl.Cell(1,1).Range.Start);
rng.Select();