How do i group columns using Excel interop?
if i record a macro (usually a good way to get started) i get this code:
Columns("I:M").Select
Selection.Columns.Group
unfortunately this doesn't work due to several problems, at least in C++. First of all, Application.Selection returns a normal Range, then Range.Columns is another Range. And Range.Group is this method:
http://msdn.microsoft.com/en-us/library/microsoft.office.interop.excel.range.group%28v=office.11%29.aspx
This method only works in connection with pivot tables.
So how do i create a column group using Excel interop?
Even if i manage to create a group, how can i shrink/expand it? By that i mean clicking on the + to show the content of the group, or rather the other way around, "click" on the minus to hide the group. If i do that while recording a macro, it is not reflected in the macro at all.
Despite the fact that the Range.Group() documentation appears to relate to pivot tables, if you extract the columns using Range.Columns, and then apply the .Group() method to that range, it will have the desired effect. In C#:
Range range = sheet.get_Range("c1","e1");
range.Columns.Group();
Edit: The complete example, again in C# (apologies, it's the example I have handy):
Microsoft.Office.Interop.Excel.Application app = new Microsoft.Office.Interop.Excel.Application();
app.Visible = true;
app.Workbooks.Add();
Worksheet sheet = app.Workbooks[1].Sheets[1];
Range range = sheet.get_Range("c1","e1");
range.Columns.Group();
One thing the macro recorder obscures is the need to use the Range.EntireColumn property. Here's some code that groups, expands and collapses. I got this by googling and fooling around, but I think it gets the concepts right. Hopefully it's easy to translate into C++:
Sub test()
Dim ws As Excel.Worksheet
Set ws = ActiveSheet
With ws
If .Columns.OutlineLevel > 1 Then
'clear any existing hidden grouped columns and grouping
.Outline.ShowLevels columnlevels:=.Columns.OutlineLevel
.Range("1:1").EntireColumn.Ungroup
End If
'group
.Range("A:C").EntireColumn.Group
'collapse
ws.Outline.ShowLevels columnlevels:=1
'expand
ws.Outline.ShowLevels columnlevels:=.Columns.OutlineLevel
End With
End Sub
Related
SOLVED USING A DIFFERENT APPROACH (see at the end)
I am trying to combine some queries into one by using the Table.Combine() function.
If I explicitly write the name of each query (e. g., Table.Combine({#"Name of query 1", #"Name of query 2"})) and then apply the changes, everything works fine.
However, since I want to make it dynamic, instead of writing a list of names, I pass the function a list of tables generated in a previous step:
So after I get this table, the next step is: = Table.Combine(PreviousStep[Value]). Note that Value is the name of the column that contains the tables. Apparently, by doing so this column of a table containing tables is converted to a list containing tables. This works fine (I can preview the resultset) until I hit that Apply changes button. When I do it, this message pops up:
I had a look at these threads: https://community.powerbi.com/t5/Desktop/We-cannot-convert-the-value-null-to-type-Table/td-p/391064, https://community.powerbi.com/t5/Desktop/We-cannot-convert-the-value-null-to-type-table/m-p/346056, but it didn't work. I've tried other approaches as well.
Further information:
Power BI Desktop version: 2.106.582.0 64-bit (June 2022)
Data source: combining existing queries that come from a single Excel file.
Steps followed to get that list of tables that I pass the Table.Combine() function:
let
Origen = #sections[Section1],
#"Convertido en tabla" = Record.ToTable(Origen),
#"Errores quitados" = Table.RemoveRowsWithErrors(#"Convertido en tabla", {"Value"}),
Personalizado1 = Table.SelectRows(#"Errores quitados", each Text.StartsWith([Name], "COMPRAS Y GASTOS")),
Personalizado2 = Table.Combine(Personalizado1[Value])
in
Personalizado2
I access all the queries I have (with the #sections keyword), convert it to a table, remove possible errors, filter to get the queries I want (the ones starting by "COMPRAS Y GASTOS") and then try to combine the queries).
A DIFFERENT APPROACH
What I wanted to do was merge tables that came from an Excel file, each of them referring to a year (2019, 2020, 2021, 2022). But I also wanted the combined table to update when new sheets were added on Excel (2023, 2024...).
I've tried many different approaches, like generating a dynamic list (from 2019 until the current year)... but for some reason none of them worked, even though the code apparently is correct.
So my new approach has been to create a sufficient amount of Excel sheets for the coming years (that are now empty, but when the new year comes the information will be filled in there), to create the queries referring to those sheets (they return empty tables) and merging those existing (but empty) tables with the ones from 2019-2022. This way, when data from 2023 is filled in in the sheet, the query is updated and it works.
It's a shame I couldn't actually solve the original problem I had, but this approach works.
In my project I have to create my own multiple sorting and multiple grouping dialogs. Basically user can choose which columns should be included, select order and direction of operation.
For multiple sorting I use this function and it works
.igGridSorting( "sortMultiple", [exprs:array] );
The problem is now with grouiping. Is there any function which will behave similary? I mean executing with array of grouping expressions (which define columns to group by, order of grouping and direction of grouping (acs / desc)) as parameter? (this feature is supported by ignite-ui built-in dialog)
In the documentation I have found:
.igGridGroupBy( "groupByColumns" );
The description is "Adds a column to the group by columns list, executes the group by operation and updates the view."
But there is nothing about how add this columns.
There is no public API method for grouping multiple columns.
The build-in dialog sets the expressions into the datasource and also takes care to rebind the grid and rebuild the grouping area. Unfortunately none of this is exposed as public API.
So the easiest approach would be to go around the columns you need to group and invoke groupByColumn for each column.
Another thing you can do is to re-create the grid with another set of columnSettings for the GroupBy feature.
I am creating an excel sheet with following Data Validation drop down list.
NA
Done
(add some formula here)
Basically, i will be able to select either plain text "NA"/ "Done" from the dropdown list. But sometimes, I want the user to be able to calculate some values based on the cell respective to the row selected so, I want to have one formula as a choice inside the data validation dropdown list. Is this possible?
Data Validation List Source
When I click on Formulae option, it should execute the formula with respect to the cells in that Row
But currently, the formula that i put in doesn't execute, instead it will just show the whole formula in the cell when activated.
1)How can i make it so that when i select the formula from data validation list, it will execute it instead of filling up the cell with it?
2)How do i set the formula so that it will be using the cell from the current Row? (for example, if i am using the data validation List in N60, the formula should adapt itself to use the cell (let's say A60?).
I may not be able to help with the second part, but I was seeking an answer to the first and discovered a solution/workaround using Name Manager.
First, in Formula > Name Manager, create a new reference (the "refers to" will contain whatever formula you are wishing to ultimately display in the validation list. For this example, we use the formula reference "=IF($H54=..." and Name it "UniqueName"
Now, we go into Data Validation, Select List, and input the three items we want displayed in the list, with an equals sign preceding our newly named reference: ie. "NA,Done,=UniqueName"
Note: You can't start with the =UniqueName or validation will try to read it all as a formula and fail.
This method will allow the user to display "NA", "Done", or "=UniqueName" in the cell; if "=UniqueName" is selected, the cell itself will interpret this as a formula and execute it accordingly, displaying the results of "=IF($H54=...", or whateverelse you have designated to use as a named formula.
If it's too late for yours, I hope this helps someone else who may face a similar problem.
While I think I know what you're trying to say. Why don't you just use an IF formula to evaluate everything instead of selecting a drop down for every row manually. You already had it partially solved using IF. Just need to add the criteria for a "Done" and an "NA"
=if(A1="date","Done",if(A1<"date","NA",if(something else until you have all your catergories))
Just going to piggyback off of Mark's response.
If you really needed your named formula to be the first selection in the list, you can setup your list with a leading comma like so:
,=UniqueName,NA,Done
That worked out for my use, and there was no null item listed in the Data Validation drop down. Hope that helps!
Is there any way to group a table by a text field, having in count that this text field is not always exactly the same?
Example:
select city_hotel, count(city_hotel)
from hotels, temp_grid
where st_intersects(hotels.geom, temp_grid.geom)
and potential=1
and part=4
group by city_hotel
order by (city_hotel) desc
The output I get is the expected, for example, City name and count:
"Vassiliki ";1
"Vassiliki";1
"Vassilias, Skiathos";1
"Vassilias";5
"Vasilikí";25
"Vasiliki";23
"Vasilias";1
But I'd want to group more this field, and get only one "Vasiliki" (or an array with all, this is not a problem) and a count of all the cells containing something similar between them.
I do not know if could this be possible. Maybe some function to text analysis or something similar?
SELECT COUNT(*), `etc` FROM table GROUP BY textfield LIKE '%sili%';
// The '%' is a SQL wildcard, which matches as many of any character as required.
You could do something like the above, choosing a word for the 'like' that best fits the spellings that your users have used.
Something that can help with that would be to do a
SELECT COUNT(*), textfield FROM table GROUP BY textfield ORDER BY textfield;
And selecting the most 'average' spelling for your words.
Otherwise you're starting to get into a bit of language processing, and for that you will want to write some code outside of SQL.
This would be something like https://en.wikipedia.org/wiki/Damerau%E2%80%93Levenshtein_distance
To find word's that are the same within an arbitrary margin of error.
There is a MySQL implementation here that you should be able to transpose as needed
https://stackoverflow.com/a/6392380/1287480
(credit https://stackoverflow.com/a/3515291/1287480)
.
(Personal thoughts on the topic)
You Really Really want to think about limiting the input from users that can give you this issue in the first place. It's far far better to give the users a list of places to select from, than it is to push potentially 'dirty' information into your database. That eventually always winds up with you trying to clean the information at a later time. A problem that has kept many people employed for many years.
I have a situation where I'm using the IEditorDataFilter interface within a custom UltraGrid editor control to automatically map values from a bound data source when they're displayed in the grid cells. In this case it's converting guid-based key values into user-friendly values, and it works well by displaying what I need in the cell, but retaining the GUID values as the 'value' behind the scenes.
My issue is what happens when I enable the built-in group by functionality and the user groups by a column using my editor. In that case the group by headers default to using the cell's value, which is the guid in my case, so I end up with headers like this:
Column A: 7F720CE8-123A-4A5D-95A7-6DC6EFFE5009 (10 items)
What I really want is the cell's display value to be used instead so it's something like this:
Column A: Item 1 (10 items)
What I've tried so far
Infragistics provides a couple mechanisms for modifying what's shown in group by rows:
GroupByRowDescriptionMask property of the grid (http://bit.ly/1g72t1b)
Manually set the row description via the InitializeGroupByRow event (http://bit.ly/1ix1CbK)
Option 1 doesn't appear to give me what I need because the cell's display value is not exposed in the set of tokens they provide. Option 2 looks promising but it's not clear to me how to get at the cell's display value. The event argument only appears to contain the cell's backing value, which in my case is the GUID.
Is there a proper approach for using the group by functionality when you're also using an IEditorDataFilter implementation to convert values?
This may be frowned upon, but I asked my question on the Infragistic forums as well, and a complete answer is available there (along with an example solution demonstrating the problem):
http://www.infragistics.com/community/forums/p/88541/439210.aspx
In short, I was applying my custom editors at the cell level, which made them unavailable when the rows were grouped together. A better approach would be to apply the editor at the column level, which would make the editor available at the time of grouping, and would provide the expected behavior.