Insert or update cells ([Range]) from one sheet to another - vba

I have a vba code that gets specific range from inputsheet and then pastespecial with xlValue to just copy the values.
However, I want that if the macro runs again, it should update value if already in outputSheet otherwise insert.
what is the best way to do it?
I want to avoid looping cells for performance.
I can modify the existing copy process to include some metadata with the values, like sourceCell.address. but with any metadata, i would still want to avoid loop.
Is there any recommended way of doing this?

Related

Formatting Data in excel sheet with blue prism

I'm trying to run a duplicate check In which varying data is pulled from a website and compared to a master list, the master list being stored in Excel. The information from the website is read from a table in which has line breaks. These breaks are translated over to the data collection they are initially stored in. Some of the data from the website us eventually written to the master list in Excel. So when I read the master list back into Blue Prism to run a duplicate check, the rows that have line breaks are written into a collection as multiple rows (ex. I should have on 7 rows in my collections but am getting 42). Since the rows are not EXACTLY the same between the 2 collections, when it runs the automation does not recognize the duplicates.
The easiest way to solve this would be if I could make the collection rows have no line breaks as soon as the data is read. I've attempted to use the calculation stage to do so with no luck. I'm not sure if it is actually possible to do this, but would appreciate any direction.
Record an Excel macro to do the data sorting/cleaning in Excel (possibly Text To Columns, etc..) and then include the running of the macro as part of your Blue Prism process by using an action stage and the MS Excel VBO - Run Macro. Get the process to create an Excel instance (and create a handle data item from that stage), then use Open Workbook (whatever workbook you store your Macro in) and then use the MS Excel VBO - Run Macro (use the same handle created earlier and type in the name of the "macro").
It sounds like what is happening is that the MS Excel VBO is grabbing the data from the Excel Worksheet wholesale.
This is to say that it's accessing your Worksheet table, copying the cell values BUT not the cell formatting data, and then dumping the values into a BP collection.
Since it did not bring along any of the original cell formatting data to reference when it went to populate the collection it's just breaking up the values based on crturn/line breaks. Thus, your collection is organized based on that, and not on the original Worksheet cell.
So, with that said, on to a solution!
Solution 1
Brute force the organization of the incoming Excel cell data to the collection by looping over the Excel Worksheet cell-by-cell.
Run a loop, and in that loop have BP go into the Excel Worksheet and grab the first populated cell it comes across. Run a formatting/cleanup Calculation stage over the data. Dump the cell value into a single collection field.
Repeat.
This is...inelegant, expensive at best, and not at all recommended for any medium to large dataset. But it's definitely the best way to do string manipulation and value comparisons before it hits your collection. Since it sounds like your using a Master template then you as-well know what the expected format of your data should be.
This method will enable you implement Trim(), Concat(), or Split() in a Calculation stage to better organize your incoming data before you dump it into a collection.
This is also basically what I think you're already trying to do, but cell-by-cell instead of Worksheet row-by-row or table-by-table.
Solution 2
Clean up the table data you grab from the website before you dump it into the Excel Worksheet.
This is basically Solution 1, but in reverse. Simply format/cleanup your data before it hits you Excel Worksheet.
I'm not sure this is any better than Solution 1, but, you know, it's something...
Solution 3
Format the cell data IN the MS Excel Worksheet itself.
Basically rearrange the cells and cell data in the Excel Worksheet into a more predictable format by using the Split, Trim, Merge, or other actions included in the MS Excel VBO. You can also do this using the Data - OLEDB utility object, but that requires some pretty solid understanding of SQL syntax.
This would look like this using the MS Excel VBO:
Grab the Excel Worksheet data wholesale and dump into a collection
Count the rows/fields of the collection
Is that number consistent with the desired/expected format of your data?
If not, have the bot go back into the Excel Worksheet and reformat the cells by removing any carriage returns/line breaks/whatever else
Repeat.
However, I'm always reluctant to reformat any original source, as it's then hard to figure out what wrong and where it went wrong when you've changed the original structure of your data. So it's best to always make a copy of the Worksheet before you make any manipulation.
Unfortunately I don't have access to my BP environment at the moment or I'd provide you with the act object actions you'd need to do any of this, my bad. Once I do I'll update this answer.

Display change in value of a cell in adjacent cell using excel VBA

I have a excel sheet that display's price on certain items in a column by looking up amazon API using excel vba. The price of may change overtime. So I am trying to display the difference in prices each time i run my macro, in a cell adjacent to the cell that displays price.
But I am not sure how to achieve this. Can any body guide me on how to achieve this?
This is just a sample, it must be adapted to your schema and data layout. Say the prices are stored in column A from A1 to A100. Say you already have a macro called RefreshData() that updates column A. In B1 enter:
=C1-A1
and copy down. This macro store the current values in column C before refreshing the data:
Sub DoUpdate()
Range("A1:A100").Copy Range("C1")
Call RefreshData
End Sub
Column B will display the price difference.
Something like this?
Let's say your data are in a range A2:A10
Dim rng as Range
Set rng = Range("A2:A10")
rng.Offset(0,1).Value = rng.Value
Run this before you run your original macro to store the values in an adjacent column before the values change. You may need to make the range dynamic, depending on your needs.
Without seeing you code, I cannot give a detailed answer. However, I ran across a similar problem once, not using Amazon API though, but a sharepoint connection.
If the amazon api is somewhat similar to the sharepoint stuff, I guess it refreshes cells when you click "update", or run the update sub. In that case you will have to either create an array to store the old prices in vba (very slow process), and then write them to your table, or create a separate tab where you store the item-lastPrice combination.
I ended up storing not only current price but all prices and the date/time of the price, to be able to see change over time.
For the copying of data itself using VBA, either of the above methods should work. In my initial code I used vba loops :-p, but copying using excel functionality is much faster.

Unable to move / delete rows in shared workbook - Not enough resources

this one's a bit of a painful one so thank you for your help and patience with me.
We have an Excel spreadsheet that we use as a master file for our website products. As such there are quite a few sheets and quite a few products on each running along side some macros to provide some extra functionality (turning entered data into HTML for product page, etc).
My issue is that one of our most used spreadsheets has become a trouble in that it has some phantom formatting all the way down to the millionth-and-something row and all the way across, causing the last cell to be the very last cell possible.
The issue that has finally popped up as a result is that we can no longer move rows in, out or around the sheet (a required functionality) as it results in an 'out of resources error'.
I've tried:
Highlight all rows below used range to right-click> delete - Results in runtime error (from macro)
Highlighting large chunks of rows and using Clear All - Resulted in the 38MB file bloating to 380MB
Deleting a chunk of rows at a time - Maxed out at 1,000 before it caused Excel to crash
Moving to new spreadsheet - Broke all our macros (which I did not write and am not proficient enough to fix on a new sheet)
Disabling macros and trying the above options, only marginally more efficient but still out of resources
I'm at my wits end on this one and, while we can continue with most day-to-day functions, we will soon be completely unable to use this particular sheet as we need it at all.
I'm wondering if there might be a way to run a VBA script to remove these rows, potentially one by one? I've tried running a short script that went something like rows[960,1000000].Delete (forgive my terrible VBA markup), but this also resulted in not enough resources errors.
I'm wondering if there's anything like:
row = 960;
while(row<=1048576){row.Delete};
Continuing, the runtime error debug points me to the below if statement within the macro:
If Target.Count > 1 Then Exit Sub
Where Target is the variable passed to the sub.
Which strikes me as very odd because my (limited) understanding of VBA and IF's in general simply recognizes that 'if my selection is larger than 1 (row?), do not run this code..
Thanks again in advance.
Use this method only if you don't have any links into or out of the sheet that will get broken. Also might have Sql connections that might get broken. Might need to disable macros. There are many possible problems with this approach. Use at your own risk.
Note the exact "Name" and "(Name)" of the sheet; Look in the VBA code window at the properties for the sheet. "Name" is the name displayed on the worksheet tab. "(Name)" is the code name visible only in the properties window.
Make a list of range names on the sheet.
Copy the data to a new sheet.
Copy any macros to the new sheet.
Delete the old sheet.
Rename the "Name" and "(Name)" of the new sheet the same as the old one.
Recreate range names.
A better method if you don't have too many formats:
Disable macros and set calculation to manual. This avoids recalculating while doing your delete operation.
Select entire sheet and clear formats.
Delete all rows below your data.
Redo your formatting. Select entire column (not just used area) to apply format if applicable.
It is important to remove formatting on the entire sheet from A1 to the end. Otherwise you'll get the bloat you mentioned. Just that step may solve your problem. If not then proceed with removing all the rows below the data. This should not cause file size bloat.

How do I select specific cells in VBA?

Basically I need to select specific cells on an excel sheet in vba. For example the code should be able to select a5, a10, a15. I do not want the cells in between them, just the ones I listed. Is there a specific function that will do this? It seems like .Range could only take start cell and ending cell.
You'd use this: Range("A5,A10,A15").Select
To add additional cells, just use more commas.
Alternately, you can utilize the Union method to join multiple range objects into a single Range object.
Note that it is generally not a good idea to select cells in VBA as nearly everything can be done without selection. This is a frequent mistake made by people new to VBA due to generated macros (Record Macro) recreating what you do rather than the result you want.

Clear cells out of the used range

In one of my macros I loop trough used range, but the used range is way bigger than the actual used range, therefore the macro is impossible to run. I think that cells outside the actual used range may have other impacts on my code such as error "too many cell format" with only one cell.
How can I clean cells outside my used range so that they are not taken into account in my Used range ?
The Used Range not truly reflecting what is the actual used range is a common issue and just requires some basic cleaning up of the sheet.
Check out this on the Microsoft Support site: http://support.microsoft.com/kb/244435
You can delete everything outside of your actual used range.
You can either do this manually with selecting a row and ctrl+shift+down (and ctrl+shift+right with a column selected) or you can do it programatically by identifying where your data actually ends (either via a COUNTA or xlRight style of command) and then delete everything after those points.
The manual way is good for if it's just a one one off cleanup operation, and if you're doing it in the macro then you may as well just use the method for determining the range to keep to go straight to selecting it, and not bothering to delete outside of the range.