I have a table on a spreadsheet and I want to delete all the existing data. I use the code below which works except when the table is already empty.
// Get the row count
let rowCount = table.getRangeBetweenHeaderAndTotal().getRowCount();
// Delete all the rows
table.deleteRowsAt(0,rowCount);
The problem is that rowCount will return 1 even if the table is empty. When deleteRowsAt tries to delete a row in an empty table it returns an error.
In VBA we can use table.ListRows.Count and this will return 0 if the table is empty.
Example: I have 3 rows in the table
If I select all the rows and delete them from the Table I get this:
This table now has no rows but I have no way to get this result. As I said, in VBA we would use table.ListRows.Count and this would return 0 but I cannot seem to find the equivalent for Office Scripts.
UPDATE:
We now have getRowCount API on the table that you can use to solve this scenario. It'll return the actual rows (not counting the header or expansion row).
// Assuming there's a table in the workbook named Table1
let rowCount = workbook.getTable('Table1').getRowCount(); // Table1
// Assuming there's a table in the workbook
let rowCount = workbook.getTables()[0].getRowCount(); // First table
====
OLD ANSWER
I think we are lacking an API that will provide row count. We'll add that to the backlog.
A workaround is this -
function main(workbook: ExcelScript.Workbook) {
let table = workbook.getTable("Table26");
let rowCount = table.getRangeBetweenHeaderAndTotal().getRowCount();
try {
table.deleteRowsAt(0, rowCount);
} catch (e) {
if (rowCount === 1 && e.code === 'InvalidArgument') {
console.log("This error means there's no row to delete.")
}
}
}
If row count is 1 and the error code is a specific one that's returned when we delete the 'insert-row', then we can ignore the error.
Again, a better approach would be to use an API on the table object to get the row count and delete rows only when row count >= 1. We'll investigate further to improve the experience.
I ran some quick tests deleting 5,000 rows (5 columns, different data types) using deleteRowsAt() and it consistently took 20 to 30 seconds. But ~10,000 rows or more and I got a timeout every time, the script never finished. Calling the script from Flow also gave me gateway timeouts with multiple reattempts before failing.
table.deleteRowsAt(0, rowCount);
But using getRangeBetweenHeaderAndTotal() to reference a range for deletion worked well, 200,000 rows of the same test data in about 2 seconds. The documentation mentions ranges are faster, they certainly are in my tests.
table.getRangeBetweenHeaderAndTotal().delete(0);
Related
Hi I am trying to change to write VBA for excel to clean up data elements that has extra information without impacting the other elements.
I am writing VBA for the first time my table is in the middle of the sheet.
Given Table and Requested Output.
I think your question was not clear in regard to the "steps" that you want to perform on your data (i.e. the exact logic or transformation that needs to be applied).
Based purely on your images and your comment, I make the "steps" to be:
Split any customer IDs in column valueC into multiple rows.
If column valueC does not contain customer IDs (i.e. is blank or contains non-customer ID text), leave it untouched.
My answer uses Power Query instead of VBA. If you are interested in trying it out, in Excel try clicking Data > Get Data > From Other Sources > Blank Query, then click Advanced Editor near the top-left, copy-paste the code below, then click Done.
You might need to change the name of the table in the first line of the code (below), as it was "Table1" for me, but I imagine yours is named something else. Also, the code below is case-sensitive. So if there is no column named exactly valueC, then you will get an error.
let
Source = Excel.CurrentWorkbook(){[Name="Table1"]}[Content],
fxProcessSomeText = (textToProcess as any) =>
let
canBeSplit = Text.StartsWith(textToProcess, "### customer id"),
result = if textToProcess is null then null else if canBeSplit then Text.Split(Text.BetweenDelimiters(textToProcess, "### customer id", " ###"), ",") else {textToProcess}
in
result,
invokeFunction = Table.TransformColumns(Source, {{"valueC", fxProcessSomeText}}),
expanded = Table.ExpandListColumn(invokeFunction, "valueC"),
reindex =
let
removeIndex = Table.RemoveColumns(expanded, {"index"}),
addIndex = Table.AddIndexColumn(removeIndex, "index", 1, 1),
moveIndex = Table.ReorderColumns(addIndex, List.Distinct(List.InsertRange(Table.ColumnNames(addIndex), 0, {"index"})))
in
moveIndex
in
reindex
My output table contains more rows than yours. Also, the value in column valueA, row 11 is 1415 for me (it is 1234 in your request output). Not sure if this is a mistake in your example, or if I'm missing some logic.
In MS Excel I have one table with few values (i.e. 3, no fix length) and in second table these values has to be repeated lot of time (i.e. 7 times). I do not understand how to provide this with normal Excel formulas/functions.
Table 1:
ABC
Table 2 (target table):
ABCABCA
how stupid am I. Is used wrong name of function index: the correct is =INDEX(Table1!A$1:A$100; 1; MOD(ROW();COUNTA(Table1!A$1:A$100))+1)
and this is added in each row of table 2
We have a spreadsheet that gets updated monthly, which queries some data from our server.
The query url looks like this:
http://example.com/?2016-01-31
The returned data is in a json format, like below:
{"CID":"1160","date":"2016-01-31","rate":{"USD":1.22}}
We only need the value of 1.22 from the above and I can get that inserted into the worksheet with no problem.
My questions:
1. How to use a cell value [contain the date] to pass the date parameter [2016-01-31] in the query and displays the result in the cell next to it.
2. There's a long list of dates in a column, can this query be filled down automatically per each date?
3. When I load the query result to the worksheet, it always load in pairs. [taking up two cells, one says "Value", the other contains the value which is "1.22" in my case]. Ideally I would only need "1.22", not the title, can this be removed? [Del won't work, will give you a "Column 1" instead, or you have to hide the entire row which will mess up with the layout].
I know this is a lot to ask but I've tried a lot of search and reading in the last few days and I have to say the M language beats me.
Thanks in advance.
Convert your Web.Contents() request into a function:
let
myFunct = ( param as date ) => let
x = Web.Contents(.... & Date.ToText(date) & ....)
in
x
in
myFunct
Reference your data request function from a new query, include any transformations you need (in this case JSON.Document, table expansions, remove extraneous data. Feel free to delete all the extra data here, including columns that just contain the label 'value'.
(assuming your table of domain values already exists) add a custom column like
=Expand(myFunct( [someparameter] ))
edit: got home and got into my bookmarks. Here is a more detailed reference for what you are looking to do: http://datachix.com/2014/05/22/power-query-functions-some-scenarios/
For a table - Add column where you get data and parse JSON
let
tt=#table(
{"date"},{
{"2017-01-01"},
{"2017-01-02"},
{"2017-01-03"}
}),
add_col = Table.AddColumn(tt, "USD", each Json.Document(Web.Contents("http://example.com/?date="&[date]))[rate][USD])
in
add_col
If you need only one value
Json.Document(Web.Contents("http://example.com/?date="&YOUR_DATE_STRING))[rate][USD]
I have an excel file which gets updated on a daily basis i.e the data is always different every time.
I am pulling the data from the Excel sheet into the table using Talend. I have a primary key Company_ID defined in the table.
The error I am facing is that the Excel sheet has few duplicate Company_ID values. It will also pick up more duplicate values in the future as the Excel file will be updated daily.
I want to choose the first record where the Company ID field is 1 and the record doesn't have null in the rest of the columns. Also, for a Company_ID of 3 there is a null value for one column which is ok since it is a unique record for that company_id.
How do I choose a unique row which has maximum no. of column values present ie for eg in the case of Company ID of 1 in Talend ?
tUniqRow is usually the easiest way to handle duplicates.
If you are worried that the first row coming to tUniqRow may not be the first row that you want there, you can sort your rows, so they enter tUniqRow in your preferred order:
(used components: tFileInputExcel, tJavaRow, tSortRow, tUniqRow, tFilterColumns)
In your particular case, the tJava could look like this:
// Code generated according to input schema and output schema
output_row.company_id = input_row.company_id;
output_row.name = input_row.name;
output_row.et_cetera = input_row.et_cetera;
// End of pre-generated code
int i = 0;
if (input_row.company_id == null) { i++; }
if (input_row.name == null) { i++; }
if (input_row.et_cetera == null) { i++; }
output_row.priority = i;
I need help.
It seems all macros I stumble upon on this website require me to write out all the rows I'm concatenating and merging. I was wondering if I could do this with a while or if statement. In the meantime,
I need to merge a table of over 21000 names (more than half of which are duplicates) but each name duplicate either has data that the original is missing, or vice versa or sometimes has different data under each column and I need to merge them. There are also like 34 (up to AF) columns.
Thanks,
Eddie
P.S. Apparently I need at least 10 reputation to post images, so message me via my account name if you want a screenshot of what I'm looking for.
P.S.S.
So after consulting with someone who helped through a comment I wrote this java-based pseudocode. Could someone help me translate it to VBA while I start to learn VBA myself? Also could they verify that it theoretically works? I'd like to have this done by the end of the day, which is why I'm asking for translation help, but I'm planning to be able to do this on my own in the near future.
//Create primary keys for comparison, using the last cell as PK for easy line finishing
//Create concatenation comparison keys (conKey) to compare cells and merge
//import new sheet and create cell location to write to new sheet.
Create PK1 = (cell) AF1
Create PK2 = (cell) AF2
Create conKey1 = (cell) A1
Create conKey2 = (cell) A2
Create newSheet = [a new sheet]
Create writeLine = A1
//Initialize while loop. This list lasts until it reaches the last person's name
While(conKey2 <= maxClient) {
//Initialize the if statement. It finds out whether merge is necessary
If(PK1.equals(PK2)) {
//Initialize while loop. This lasts until PK1 no longer equals PK2
while(PK1.equals(PK2)) {
//Initialize if loop. It checks to see if the values are not equal. if so, it concatenates into conKey1
if(!conKey1.equals(conKey2)) {
conKey1 = concatenate(conKey1,", ",conKey2)
}
//Export cell to writeLine of newSheet. Shift everything to the right. verify writeLine equals conKey1
//Clear the doubled cell for safe keeping and to assist us in closing the while loop.
exportTo(newSheet.writeLine, conKey1)
conKey1.shiftsRight
writeLine.coordinates(equals(conKey1))
conKey2 = ""
conKey2.shiftsRight
}
//After this while loop is finished, delete the blank row.
//coordinates of PK1 and PK2 should remain the same at this point
deleteRow(PK2)
//If the merge was not necessary it will skip all of that above and shift each variable down a row.
} else {
PK1.nextRow
PK2.nextRow
conKey1.nextRow
conKey2.nextRow
writeLine.nextRow
}
If SQL is a solution and MAX value of all values is an accepted value... then using an ODBC, a defined table and a self reference may work..
Select Formulas then define name
Define the range of existing data
Select where you want the combined results to display (for example Sheet 2 (A1) instead of sheet 1)
Save the workbook
Select data then from other sources.
select data connection wizard
Select ODBC DSN
Select Excel Files
Find the file saved
Now select the new table (the one defined in step 1)
and complete the wizard.
Go to data menu
Properties
click connection properties button
select definition tab.
modify command text to fit needs
It takes data from sheet 1 such as this:
And provided the wizard is completed (steps 5-11) and then the SQL updated in step 16 you'll get something like
.
This is the command text I used. since it's SQL it can be altered to fit your needs max, concat, whatever
Select firstName, MiddleName, LastName, max(attrib1), max(attrib2), max(attrib3), max(attrib4)
From `yourPath&FileName.xlsx`.`YourDefinedName`
GROUP BY firstName, MiddleName, LastName