I can't seem to locate a solution to a common scenario I face using Excel. My VBA ability is limited, so I'm not sure how to proceed with coding, but here is what I am trying to solve.
I have a spreadsheet listing rows that will frequently have additional rows mostly matching previous rows. For example, there may be two rows for the same customer, where the data is the same except that the second row has a different phone number. Everything else is the same, including a unique ID in column A. What I am looking to do is create code that will find a matching second (or additional) rows and blank any fields on the subsequent rows that match the previous, leaving any fields with different values alone.
This site won't let me insert a diagram showing what I'm talking about, but an example would be a spreadsheet with three columns- ID, Name, Phone. ID number 99 has two entries with the same ID and name, but different phone. I'd like to be able to blank the fields where the ID and name are duplicated and leave only the phone.
In this example, it's phone number, but it could be any column or combination of columns.
Is there a viable way to do this?
below has been tested:
Sub test()
For Each cell In Range("A3:C1000")
If cell.Value = cell.Offset(-1, 0).Value Then cell.ClearContents
Next
End Sub
just change Range to whichever Range you require, skipping first row(i skipped row 2) as it an anchor which is unique anyway.
P.S. this only works sequentially though so you need a sorted list
EDIT
first solution clearly was wrong, apologies, please try below, please note there is one caveat in it: if you have an entry in any particular column which repeats against some other entry which in fact is different - let say same phone number for a different customer, it will ALSO delete that entry.
it checks each entry against all previous entries in the same column, if it appeared previously, it will delete it.
Sub test()
Dim cell As Range
Dim c As Range
For Each cell In Range("A3:C1000")
On Error Resume Next
Set c = Range(Cells(2, cell.Column), Cells(cell.Row - 1, cell.Column)).Find(cell.Value)
On Error GoTo 0
If Not c Is Nothing Then
cell.ClearContents
End If
Next
End Sub
Related
Thank you in advance for your help.
The short version:
Need to have it so specific cells in a table are locked based on the what the first cell in that row contains.
The cell that is used to determine if other cells in the row are locked needs to always remain unlocked
I am working on an Excel sheet that contains a table. This table is used to record key information about products and is being updated daily. Each product is defined in its own row with columns being used to show details such as "Drawing number" and "Customer" etc.
Depending on the stage the product is at in development and how well the product went once completed, it will be labeled with a single "state" from a list such as "Ongoing", "Bad-product", "Archived" etc.
enter image description here
In each cell in each row, the text the cell contains is determined through either data validation in the form of lists or manually typed in. for example, all cells in the customer column will use a dropdown menu to select a customer from a list, but the cells in the drawing number column are always one of a kind so require manual input.
As so many people access and edit this table there are issues with mis-clicking and typing which causes data to be overwritten without someone noticing they have done so.
Because of this issue I want to be able to lock specific columns in a row based on what the first cell in the row contains ("State" column).
In the instance that the state column contains the word "archived" I want to lock the entire row from having its contents being changed.
In the case of the word being "Ongoing" I want to lock column AA and AB in that row.
As it is sometimes is necessary to go back and edit information due to a known mistake I would need to have it so the State column always remains unlocked whatever it contains.
I have attached a redacted Excel sheet that contains my attempt at a coded solution.
https://drive.google.com/open?id=1rzTp0ur1tpXIY_Wa3cVlcwruJ7Q1rT
The code can also be seen below.
Note: I was not sure how to even go about fulfilling the requirement for the "Ongoing" condition so would really appreciate it if someone could point me in the right direction
Sub Locking()
Dim KeyCells As Range
Set KeyCells = Range("A3:A612")
For Each cell In Range("A3:A612")
If cell.Value = "Archived" Then
cell.EntireRow.Locked = True
ElseIf cell.Value = "Ongoing" Then
cell.EntireRow.Locked = False
ElseIf cell.Value = "Bad" Then
cell.EntireRow.Locked = False
End If
Next cell
End Sub
This is my first post on here as I could not find the solution from looking at several different stack overflow questions. I also watched numerous videos on VBA code, but am definitely missing something, and am struggling to figure out what it is.
If I have posted this incorrectly or extra detail would be helpful, please let me know.
Any and all help is extremely appreciated!
Thank you
Edit: Code works now
Instead of locking the entire row
cell.EntireRow.Locked = False
if you just want to lock AA and AB in that row do the following:
cell.EntireRow.Locked = False 'unlock entire row first
'then lock just the 2 rows
Range("AA" & cell.Row & ":AB" & cell.Row).Locked = True
The others would work the same way.
I would like to find the text "Currency" in columns A or B, store all the currencies listed under Currency. Same process for Amount (Can be in an column)
Store values in an array. Then paste in Output Sheet. The currencies will already be listed in Output sheet in 1st row of the sheet. However if it is a new currency then the code should find last used cell in row 1 and add it. The value of Amount should be added to Output sheet against the currency and ID number also copied from the Source sheet.
I have some code.
Public Sub loopRow()
Dim curArray As Variant
Dim listarray As Variant
Dim cnt As Long
'Find Currency
Dim rgFound As Range
Set rgFound = Range("A:B").Find("Currency")
'Find last used row
curArray = Cells(rgFound.Address).End(xlUp).Row
'Transpose list of currecny from the row down from the word Currency that it has found
listarray = Application.Transpose(Cells(Rows, curArray).End(xlUp)).Row
For cnt = LBound(curArray) To UBound(curArray)
curArray(cnt) = curArray(cnt)
Next cnt
For cnt = LBound(curArray) To UBound(curArray)
'Debug.Print curArray(cnt)
'Copy and paste into Sheet under the correct curreny, if new currency then add this in row A
Next cnt
End Sub
Whilst you need to understand your question is unanswerable as is, I'll do my best to help.
The problem we have is not seeing the source sheet the way you do, as we can't see it at all. You say you have the word Currency in columns A or B or both, and an ID column somewhere, and Amount values everywhere. That's tricky source data. If as is more likely, the ID is in a specific column and the amounts are in a set of columns, then we'd have a chance.
Your question outlines the basic steps you'd want to take pretty well, so you're off to a good start.
However you can do all of the work without VBA, certainly if I'm right about the Source data. Create yourself a working sheet, or multiple working sheets. Definitely one to sort out the full list of currencies. Grab a copy of columns A and B (by formulae) and then have the working sheet go through line by line and use logic to build the list. Spreadsheets are great at this.
Once you have the list, use it as row headers on your Output sheet and use sumifs to get the values. I am not sure how the IDs would fit in, but if they were to be your row headings, then do the same as the above to get the list of unique ids and link them into your Output page in column A. Your sumifs can handle that.
That will hardly tell you all you need to know, but if you work it out you'll have learned a lot about Excel and when you need to go into VBA.
If you'd rather do it with VBA, break down each step until it works, and then go onto the next one.
And if you want more help, paste your data in here. Anonymise it first if you need to.
I have a column which contains productIDs which are similar to numbers
ProductIDS
46257547467
65464564656
47682542896
68683582757
I also converted it to text using =TEXT(cellNO,"0") and it works fine for that time. But next time after few hours when I open the file it reads that column as numbers like this:
ProductIDS
4.62E+10
6.54E+10
4.76E+10
6.86E+10
How can I permanently convert it to text so that when I open it every time it shows me the column as text ? Thanks.
It sounds like you're attempting to generate unique IDs within an Excel sheet (for use in another application, maybe...?). Using a formula here won't do much good if a) new rows are being added (particularly intermingled with existing rows), or b) the formula is based on the context of the sheet.
I've written a little sub that generates a unique ID for a given column, auto-populating it when something about that row gets populated. It works for a range of inserted rows too, not just the current row.
Private Sub Worksheet_Change(ByVal targetRange As Range)
' Confirm that the change is occuring where I want to track it
If targetRange.Column = Range("WhereChangeOccurs").Column Then
' Capture the target column holding the IDs
Dim IDRangeColumn As Integer
IDRangeColumn = Range("IDRange").Column
' Loop through each row of the target range, inserting an ID literal
For Each thisrow In targetRange.Rows
' update the ID with
' DateTime (to milliseconds) plus
' unique GUID based on system
Cells(thisrow.Row, IDRangeColumn).Value = Format(Now, "yyyy-mm-dd: hh.mm.ssss-") & Mid$(CreateObject("Scriptlet.TypeLib").GUID, 2, 18)
Next
End If
End Sub
It's pretty fast, and the uniqueness holds up even when inserting multiple rows (so far checked to about 50-100 rows at a time). This has the benefit of always generating a unique ID for a row, without needing Copy-Paste-Values; no human intervention required.
Note that the ", 18)" in the ID generation can be a longer number if you'd rather use that for uniqueness; I wanted something readable (date/time) at the beginning simply for human understandability.
I have a table, let's call it my Individuals Table, much like the one below, containing a column of individuals along with their corresponding codes listed in an adjacent cell. Codes for each individual are all listed within the same adjacent cell next to the individual's name, and separated by a carriage return.
Example table
What I'd like to do is the following:
Run through the code cell for each individual
For each code in the individual's code cell, check if this code exists in a separate Codes Table
If the code exists in the Codes Table, add n+1 to the total count for that code in an adjacent cell and add the individual's name to the list of individuals with that same code in another adjacent cell.
If the code does not exist in the Codes Table, add the code to the Codes Table, add n+1 to the total count for that code in an adjacent cell and add the individual's name to the list of individuals with that same code in another adjacent cell.
Result of running the algorithm on the example table
If a similar program can achieve the same results, then I'm open to that too.
I try to give you a possible solution, by minimizing the use of VBA code.
As starting point I would do is rearranging codes for every individuals. Keeping more codes in a single cell separed by a return it is not as easy to manage like having a single code for each cell. Of course I will keep each code associated with each individual. A way to do it is with your data is by using the formula substitute and replace the returns characters with a semicolon. The formula works this:
=SUBSTITUTE(B2,CHAR(13),CHAR(59))
B2 is the cell where you are converting returns to semicolon. You will then use this formula for all values in your B column.
Once you have replaced returns with semicolon, copy and paste values and then with the function "Text to Columns" in Data tab you will convert each cell to a series of columns (depending on how many codes you had listed in the original cell of your sheet). Now you will be in a situation where the first column you have the names of individuals, and then on the same row in the subsequent columns you have all associated codes, like in the picture here below:
In order to create a complete list of all codes you can easily copy all columns with codes. Paste the codes in a suitable space (I suggest in a new worksheet), and then with some copy and paste jobs put all codes under the same column. Select all codes and with the button "Remove Duplicates" always in the Data tab you will have a list of all unique codes included in your original table.
Then you can copy and paste the column with all unique codes you created under your "Codes" column. Now you can count the codes in the converted table with this formula:
=COUNTIF($B$1:$C$4, D2)
Where first argument of COUNTIF refers to the codes in the converted table and the second argument is a code in your column "Codes" where you pasted the unique codes.
Now as far as I know there is no function in Excel to create a list of names separated by commas (but I would be glad to discover that it exists if anybody knows!!!). Therefore I created a custom one with some VBA code with the name List Individuals:
Function ListIndividuals(refCode, NameRange As Range, CodesRange As Range) As String
'Check size in row number of NameRange and CodesRange is same, otherwise give error
If NameRange.Rows.Count <> CodesRange.Rows.Count Then
ListIndividuals = CVErr(xlErrRef)
Exit Function
End If
result = ""
For Col = 1 To CodesRange.Columns.Count
For n = 1 To CodesRange.Rows.Count
If CodesRange.Cells(n, Col).Value = refCode Then
If CodesRange.Cells(n, Col).Value <> "" Then
If result = "" Then
result = NameRange(n)
Else
result = result & ", " & NameRange(n)
End If
End If
End If
Next
Next
ListIndividuals = result
End Function
So last step is to use this formula under your "Individuals" cells as follows:
=ListIndividuals(D2,$A$13:$A$16,$D$13:$E$16)
Where first argument is the Code, the second one is the list of individuals in the converted table (it should be the first column), then the third one are the columns with the codes in the converted table. As a result of this custom formula you will have the list of individuals separated by commas.
All above works on my computer, but if you need more information, please do not hesitate to contact me.
I admit I am completely new to Excel VBA. At the moment, I am in charge of generating a summary of data based of an automatically generated table of data spit out on a site. I already figured out how to scrape the data onto my Excel thankfully.
The scraped data is something of the following format:
TYPE | Number_Days_Logged | (a bunch of other important columns of data in row (6-7 items)|
What I need to do now is the following.
I need to do an if statement or comparison. There are two "types" under the type column. Let's say 0 and 1. I really only need type '1', so I need to filter out any 'type' 0's. Then I need to check the "number_days_logged". If this number is <= 1, I need to add it to a table with other entries with this condition. I then need to check "number_days_logged" for entries >= 85 and <100. These results will need to be put into a second table. Finally, I need to do the same this for values >= 100.
So in the end I need three different tables, the first with a green color formatting, then orange, and finally red. Each table need to be titled with the above information, though I really only need data from specific columns in each row. (each row is labeled, I just need a specific few columns)
This seems incredibly complicated to me, but I am willing to learn. If anyone can prod me in the correct direction, or make it simpler I would appreciate it. I can add any other details as required.
I think select statements are pretty clear and they tend to run a little faster too.
dim typeRange as range
set typeRange = range(cells(startRow,col),cells(stopRow,col))
dim entry as range
dim currentRow as integer
for each entry in typeRange
currentRow = entry.Row
if entry.value=1 then
select case cells(currentRow,'Number_Days_Logged's column').value
case is<=1
'copy and paste or transcribe the cells however you need them done.
case is<85
'do nothing
case is<100
'copy and paste or transcribe the cells however you need them done.
case is>=100
'copy and paste or transcribe the cells however you need them done.
end select
end if
next
You would first setup the tables with the colors you wanted, and (for this code) a named range for the data. I'd probably used named ranges for your tables also. Here's the skeleton of the VBA code.
Dim testrow As Range
For Each testrow in ActiveSheet.Range("Scraped Data")
If testrow.Cells(1) = 1 Then
If testrow.Cells(2) <= 1 Then
<add to 0-days table>
ElseIf testrow.Cells(2) >= 85 AND testrow.Cells(2) < 100 Then
<put in 2nd table>
ElseIf testrow.Cells(2) >= 100 Then
<put in third table>
End If
End If
Next testrow