I have a problem with automating Excel that I cannot solve. I want to mimic the "Import External Data" feature. It works already perfectly for flat tables, but not for PivotTables, when I select multiple database tables for the import.
The manual way
I have an Access database with 2 tables (accounts and transactions), linked by a foreign key ("account" in transactions table). I want to import both immediately to a PivotTable. The usual way would be to click on "Data" -> "External Data", then select both tables in the dialog, then choose "PivotTable report" and click "OK". Now the PivotTable is in the active sheet and on the right side there is the Field List which offers all fields in the hierarchy of the imported tables.
This is what I want to mimic for the mentioned database file. Does anyone have an idea how this works?
What I tried
I have already tried to record and adapt a macro, to no avail, as it records incomplete and flawed code. Incomplete because the recorded code does not feature the creation of a data model, but that is obviously necessary (?). Flawed because the code does not run, its syntax is incorrect.
I can successfully create a PivotTable from one database table like this:
Excel.PivotCaches pivotCaches = workbook.PivotCaches();
Excel.PivotCache pivotCache = pivotCaches.Create(Excel.XlPivotTableSourceType.xlExternal,
Type.Missing, Type.Missing);
pivotCache.Connection = conStr;
pivotCache.MaintainConnection = true;
pivotCache.CommandText = "Accounts";
pivotCache.CommandType = Excel.XlCmdType.xlCmdTable;
Excel.PivotTables pivotTables = sheet.PivotTables();
Excel.PivotTable pivotTable = pivotTables.Add(pivotCache, sheet.get_Range("A3", "C20"), "Pivot", Type.Missing, Type.Missing);
But it fails in each of the many attempts I tried to get more than one database table.
What is the way to go for multiple tables?
Bear in mind that I do not necessarily know the table names and the join fields, plus I do not want to lose the distinction between the tables, it should be preserved in the PivotTable field list for hierarchical choice of the fields. Furthermore, a catch-all SQL query would be a serious impairment to performance.
Please help me!
PS: I am on Office 2013 with C# as my language of choice.
/edit1: Later I would also want the PivotTable to refresh if the database tables change (manually invoking that refresh).
/edit2: I would also be entirely satisfied with a way to use multiple worksheets as sources for a PivotTable, as long as they appear separately in the Field List.
Related
I have a table in an Excel worksheet where I need to programatically remove entire rows using VSTO. After a lot of searching here and everywhere else, I was unable to find the answer. Due to some unrelated code, I also cannot delete the first row of the table, but need to remove all other rows.
Here are the specific requirements:
One of the functions of this addin is to populate the table. This is done through a loop starting with the "root" named range in the left column of the first row of the table.
Whenever populating the table, I first need to delete all data from the table and then add the new data. I need to use the "root" to add the data, so I can't have it deleted.
I am using the Table for the automated formatting instead of formatting the table manually after adding each cell.
I never know how many rows will be added, but it will always be at least one.
After banging my head on this for a few hours, I slept on it and came at it refreshed this morning. After much trial and error, here is the code I came up with.
var deplTable = ThisSheet.Evaluate("DeploymentTable");
if (deplTable.ListObject.ListRows.Count > 1)
{
do deplTable.ListObject.ListRows[2].Delete();
while (deplTable.ListObject.ListRows.Count > 1);
}
NOTE: ThisSheet is set to the correct sheet earlier. The application works on multiple sheets, so it needs to be flexible.
I tried this a few ways before finally getting it to work. Looping through the rows gave unexpected results; possibly due to timing issues between Excel and VSTO.
Hope this helps other people!
With ClosedXML I am trying to add data to an existing Excel Sheet In an Existing Table. The easy thing to do is to add a table to an excel sheet below is a quick example of how to do that. What I don't understand is if you already have a Table there that is empty how can you just add to the existing table?
// Add a DataTable as a worksheet
wb.Worksheets.Add(dataTable);
I don't know how this question isn't clear to people. If there is an existing Table (created in Excel by going to "Insert -> Table") and you open an Excel document using ClosedXML, adding data to the next row does not automatically expand the Table.
You can expand it prior to adding the data as such:
IXLTables tsTables = thisSheet.Tables;
IXLTable firstTable = tsTables.FirstOrDefault();
if (firstTable != null)
firstTable.InsertRowsBelow(1);
I had a similar requirement, where I needed to insert data into an existing Table, which had a number of data validations / comments / formula built in.
I found that the easiest solution (for me) was to use the Table's ReplaceData call. This is particularly useful if you provide a name for your Table in the Excel worksheet, as that way you can get a reference to the table directly from the workbook, ie:
var candidateTable = workbook.Table("Candidates");
candidateTable.ReplaceData(candidateData, propagateExtraColumns: true);
Note that the key to getting this to work properly is to set the propogateExtraColumns parameter - this will ensure any formula / etc you have set will automatically be copied to any new rows that are created.
FYI - you can set the Excel Table's name by selecting your table in the worksheet, clicking the Design tab, and then entering a table name:
To add a DataTable to an existing worksheet use this:
wb.Worksheet(1).Cell(1, 1).InsertTable(dataTable);
More info in the documentation.
Excel 2010.
I have a C# app that has a dataset with multiple tables. I want to export this to a workbook where each table is a separate sheet it is important to keep the order of the datasets, and the name of the data tables)
One possible solution is to loop through each table, put it on its own dataset, save this dataset as XML, then use the Application.Workbooks.OpenXML method
MSDN OpenXML Documentation
But here is the problem, if I pass the third parameter (which gives a very nice import with filters and everything), excel succeed, but it warns me that some columns were imported as text, which is ok with me (one of the columns is UPC, which should be a text, not a number).
By displaying this message it stops the process until the user clicks that this is acceptable. Then I question my self about how the mother of all excels is doing these days.
How to prevent this message from popping up?
Or another way to do this import with such nice results? (Copy and paste works but not so nicely, writing in every cell using automation is way to slow, maybe using some excel library...)
You turn
Try
var excelApplication = new Application { DisplayAlerts = false };
or
Workbook excelWorkBoook = excelApplication.Workbooks.Open(...);
excelWorkBoook.CheckCompatibility = false;
I am making an add-in and I am trying to format the output which my add-in generates,using Format as table table-styles provided by Excel.
The one which you get on the 'home tab' --> 'Format as Table' button on the ribbon.
I am using following code:
SourceRange.Worksheet.ListObjects.Add(XlListObjectSourceType.xlSrcRange,
SourceRange, System.Type.Missing, xlYesNo, System.Type.Missing).Name =
TableName;
SourceRange.Select();
SourceRange.Worksheet.ListObjects[TableName].TableStyle = TableStyleName;
TableStyleName is any style name like TableStyleMedium17, you get it if you just hover a particular style in Excel.
My problem is that, even if I keep the SourceRange as 10 columns, all the columns right till the end get selected and are considered as one table.
Because of that the table I populate right next to it is also considered as a part of the first table that was generated.Since, both the table have same column names excel automatically changes the column names in all the following tables that are generated.
Also, because I am generating the tables in a loop after 2 tables are generated I get the error :
A table cannot overlap another table.
PS: I am clearly mentioning SourceRange as:
var startCell = (Range)worksheet.Cells[startRow, startCol];
var endCell = (Range)worksheet.Cells[endRow, endCol];
var SourceRange = worksheet.get_Range(startCell, endCell);
Kindly suggest a way out.
We were able to figure out what was happening on our end for this:
on the
xlWorkbook.Worksheets.Add([before],[after], Type.Missing, Type.Missing)
call, we had to flip before and after since we wanted the sheets to move right, not left and then accessed
xlWorkbook.Worksheets[sheetCount]
by increasing sheetcount for however many sheets were being generated.
Having it the other way was creating the worksheet to access a previously assigned table formatfrom the SourceRange.Worksheet.ListObjects[TableName].TableStyle = TableStyleName call.
So, I got around this problem a week after posting this, sorry did not update in the rush of things.
This actually is an in built excel functionality.
You cant help it, the excel application will keep doing this.
So, ultimately wrote my own table styles in c# and applied it to the excel range which is mentioned as SourceRange. Its just like writing CSS.
If you are interested in knowing the details of that comment it on this question itself or you can contact me by email from my profile.
Is it possible to set foreign key between two excel sheets and query records from the two sheets?
I got an excel sheet of Student Details and another sheet consists of the total marks. Fields common to both the sheet is the RegID. I need to display the Name and Marks from the two sheets on a grid...How can it be done? please help....
Query = "SELECT Status from [Viewer$] as a LEFT JOIN [UI$] as b ON a.[Responsible Person] = b.[Responsible Person] where b.[Responsible Person] = null" ;
This query is not returning the records to a dataset...
If you mean to read Data from two Sheets and mix it to make "combined" records which you enter in the Database where you have the FK set then it should be possible.
Read Reading Excel Cells using C#
You can open who sheets which you access in a Loop, but you will have to coordinate the Data building from your sheets.
NewBie,
I've used the excel 2007 openxml sdk (DocumentFormat.OpenXml) to great effect in this scenario. It's basically a LINQ library that takes the excel docs into objects and allows you to query inside c# just like any other LINQ object. Microsoft actually do have (after a quick search) a pretty good 'idiots guide' on this topic. You can find it here:
[edit] - added a few more links
http://msdn.microsoft.com/en-us/library/dd920313%28v=office.12%29.aspx
http://blogs.msdn.com/b/johnrdurant/archive/2010/02/19/excel-open-xml-linq-part-i.aspx
http://www.briankeating.net/blog/post/2010/04/26/Linq-to-Xlsx.aspx
if you use LINQ, it's a no brainer and is definately the only way that I would go with this type of task. It will also 'cater' for you idea of fk's as it will allow you to 'join' on any arbitary field that you care to define (i.e. as with any LINQ query), thus it should address your requirement perfectly.
Not possible using SQL. Neither UNIQUE nor FOREIGN KEY is supported where the data source is an Excel workbook.