Is there any way to add the location of a cell into a SUM formula?
I have the following For Each ... Next loop, but instead of merely counting the number of cells that contain a value of 1, I would like to add the specific location of such a cell into a SUM formula.
Dim rng As Range, cell As Range
Set rng = Range("I3:DC70")
For Each cell In rng
If cell.Value = 1 Then Range("DF4").Value = Range("DF4").Value + 1
Next cell
Is this possible?
You will have to use .Find and .FindNext. You can read about it Here. This approach is much faster than looping when you have a large dataset.
Here is something that I wrote quickly. Please amend it to suit your needs.
Sub Find_Cells_Which_Has_My_Damn_String()
Dim WhatToFind As String
Dim aCell As Range, bCell As Range
Dim SearchRange As Range, rng As Range
Dim ws As Worksheet
'~~> Set this to the relevant worksheet
Set ws = ThisWorkbook.Sheets("Sheet1")
'~~> Set here what to find
WhatToFind = "1"
'~~> Set this to the relevant range
Set SearchRange = ws.Cells
Set aCell = SearchRange.Find(What:=WhatToFind, LookIn:=xlValues, _
LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
If Not aCell Is Nothing Then
Set bCell = aCell
Set rng = aCell
Do
Set aCell = SearchRange.FindNext(After:=aCell)
If Not aCell Is Nothing Then
If aCell.Address = bCell.Address Then Exit Do
Set rng = Union(rng, aCell)
Else
Exit Do
End If
Loop
End If
If Not rng Is Nothing Then MsgBox rng.Address Else _
MsgBox "No cells were found containing " & WhatToFind
End Sub
Screenshot
Related
I am looking for some assistance... Below is a code and some images of what I am attempting to acheive. I have created a selector which when you enter a qty. I want it to take the line with the quantity included and take it to another sheet on the next available line. My code is not yielding an error but neither is it doing anything at all.
I wish to take range J:P of the line with a qty entered and then paste it into the other worksheet in the next blank row of column D as there will be entries already included in A-C. Can anyone here help?
Sub Add()
Dim searchRange As Range
Dim foundCell As Range
Dim mysearch As Integer
Dim iRow As Long
Dim ws1, ws2 As Worksheet
Set ws1 = Worksheets("Output")
Set ws2 = Worksheets("Selector")
iRow = Sheets("Output").Range("D2").End(xlUp) + 1
mysearch = Sheets("Selector").Range("N10").Value
With Sheets("Selector")
Set searchRange = Sheets("Selector").Range("N12:N35") ', .Range("A" & .Rows.Count).End(xlUp))
End With
Set foundCell = searchRange.Find(what:=mysearch, Lookat:=xlWhole, MatchCase:=False, SearchFormat:=False)
If Not foundCell Is Nothing Then
ws1.Cells(iRow, 4).Value = foundCell.Offset(0, -4).Value
'and so on
End If
End Sub
This is the selector
This is where I would like to paste the values (in a different order).
Try the following, I've simply amended your code slightly, and I believe it should work as expected:
Sub Add()
Dim foundCell As Range
Dim mysearch As Integer
Dim iRow As Long, Last As Long
Dim ws1 As Worksheet, ws2 As Worksheet
Set ws1 = Worksheets("Output")
Set ws2 = Worksheets("Selector")
iRow = ws1.Cells(ws1.Rows.Count, "D").End(xlUp).Row + 1
Last = ws2.Cells(ws2.Rows.Count, "N").End(xlUp).Row
mysearch = ws2.Range("N10").Value
Set foundCell = ws2.Range("N12:N" & Last).Find(what:=mysearch, Lookat:=xlWhole)
If Not foundCell Is Nothing Then
ws1.Cells(iRow, 4).Value = foundCell.Offset(0, -4).Value
End If
End Sub
I have a spreadsheet of data that has the best part of 120 columns of data in it of which I don't all of them, so for file size I delete the ones I do not need. I figured this could be automated and have put together a VB function based on a script I found online which checks column headings against a list of values and if that value is in the list, it deletes the column.
As the column count in the spreadsheet changes due to updates, rather than fix the column reference in the code, I input a start and end column into two cells which the VB code reads but for some reason, I get an error when I select the exact column count. If I choose a smaller column count (ie: table is columns D:K and I choose D:F) the code runs fine and the columns are deleted. Can anyone maybe explain where the code is falling over as I am a newbie to VB.
Many thanks.
Here is the code I'm using and if I can figure out how to upload the example file I will do that as well:
Sub DeleteSpecifcColumn()
Dim rngFound As Range, rngToDelete As Range
Dim strFirstAddress, fstCol, LstCol As String
Dim varList As Variant
Dim lngCounter As Long
fstCol = ActiveSheet.Range("B2").Value
LstCol = ActiveSheet.Range("B3").Value
Application.ScreenUpdating = False
'varList = Range("Sheet1!B3:B8").Value
varList = ActiveSheet.ListObjects("Delete").ListColumns(1).DataBodyRange
For lngCounter = LBound(varList) To UBound(varList)
'Fixed column range
'With ActiveSheet.Range("E:F")
'Using table headings
'With ActiveSheet.ListObjects("Content").HeaderRowRange
'Cell values on sheet to build column range and then search against list
With ActiveSheet.Range(vbDblQuote & fstCol & ":" & LstCol & vbDblQuote)
Set rngFound = .Find( _
What:=varList(lngCounter, 1), _
Lookat:=xlWhole, _
SearchOrder:=xlByColumns, _
SearchDirection:=xlNext, _
MatchCase:=True _
)
If Not rngFound Is Nothing Then
If rngToDelete Is Nothing Then
Set rngToDelete = rngFound
Else
Set rngToDelete = Application.Union(rngToDelete, rngFound)
End If
strFirstAddress = rngFound.Address
Set rngFound = .FindNext(After:=rngFound)
Do Until rngFound.Address = strFirstAddress
Set rngToDelete = Application.Union(rngToDelete, rngFound)
Set rngFound = .FindNext(After:=rngFound)
Loop
End If
End With
Next lngCounter
If Not rngToDelete Is Nothing Then rngToDelete.EntireColumn.Delete
Application.ScreenUpdating = True
End Sub
Would something like this work? Assuming all of your headings are in the first row.
Sub DeleteHeadings()
Dim headingsToDelete() As Variant: headingsToDelete = Array("a", "b", "c")
Dim deletedOffset As Integer: deletedOffset = 0
For Column = 1 To ActiveSheet.UsedRange.Columns(ActiveSheet.UsedRange.Columns.Count).Column
If (IsInArray(ActiveSheet.Cells(1, Column).Value, headingsToDelete)) Then
ActiveSheet.Columns(Column - deletedOffset).Delete
deletedOffset = deletedOffset + 1
End If
Next
End Sub
Function IsInArray(stringToBeFound As String, arr As Variant) As Boolean
IsInArray = (UBound(Filter(arr, stringToBeFound)) > -1)
End Function
IsInArray function:
How to find if an array contains a string
last ued column: http://www.globaliconnect.com/excel/index.php?Itemid=475&catid=79&id=86:last-used-row-last-used-column-vba&option=com_content&view=article
If the headings only appear once you can use:
Public Sub DeleteSpecificColumn()
Dim rngFound As Range, rngToDelete As Range
Dim rDeleteValue As Range
Dim fstCol As Long, lstCol As Long
With ThisWorkbook.Worksheets("Sheet1") 'We're working with the workbook containing the code in "Sheet1".
For Each rDeleteValue In .ListObjects("Delete").ListColumns(1).DataBodyRange
With .Range("D1", .Cells(1, .Columns.Count).End(xlToLeft)) 'References D1 to last cell in row 1 containing data.
Set rngFound = .Find( _
What:=CStr(rDeleteValue), _
Lookat:=xlWhole, SearchOrder:=xlByColumns, _
SearchDirection:=xlNext, _
MatchCase:=True)
If Not rngFound Is Nothing Then
If rngToDelete Is Nothing Then
Set rngToDelete = rngFound
Else
Set rngToDelete = Application.Union(rngToDelete, rngFound)
End If
End If
Set rngFound = Nothing
End With
Next rDeleteValue
End With
If Not rngToDelete Is Nothing Then rngToDelete.EntireColumn.Delete
End Sub
If the headings appear multiple times you can use:
Public Sub DeleteSpecificColumn()
Dim rngFound As Range, rngToDelete As Range
Dim rDeleteValue As Range
Dim fstCol As Long, lstCol As Long
Dim sFirstAddress As String
With ThisWorkbook.Worksheets("Sheet1") 'We're working with the workbook containing the code in "Sheet1".
For Each rDeleteValue In .ListObjects("Delete").ListColumns(1).DataBodyRange
With .Range("D1", .Cells(1, .Columns.Count).End(xlToLeft)) 'References D1 to last cell in row 1 containing data.
Set rngFound = .Find( _
What:=CStr(rDeleteValue), _
Lookat:=xlWhole, SearchOrder:=xlByColumns, _
SearchDirection:=xlNext, _
MatchCase:=True)
If Not rngFound Is Nothing Then
sFirstAddress = rngFound.Address
Do
If rngToDelete Is Nothing Then
Set rngToDelete = rngFound
Else
Set rngToDelete = Application.Union(rngToDelete, rngFound)
End If
Set rngFound = .FindNext(rngFound)
Loop While rngFound.Address <> sFirstAddress
End If
Set rngFound = Nothing
End With
Next rDeleteValue
End With
If Not rngToDelete Is Nothing Then rngToDelete.EntireColumn.Delete
End Sub
Both sets of code start at D1 and finish at the last column containing data (or formula). The code .Cells(1, .Columns.Count).End(xlToLeft) is the same as going to cell XFD1 and pressing Ctrl+Left.
I have a specified range and want to merge the cells A-D per row. I'm not sure which loop would be the best, and have messed around with different ones and the problem I have run into, is either an object-defined error or merging the entire range into one cell.
Sub Merge()
Dim EndRangeRE As Range
Dim EndRangeNRE As Range
Dim rngall As Range
Dim StartRangeNRE As Range
Dim StartRangeRE As Range
Dim looprng As Range
Sheets("{Activity} 7300-1input template").Activate
Set rngall = Sheets("{Activity} 7300-1input template").UsedRange
Set EndRangeRE = rngall.Find(What:="10. Other Costs", LookIn:=xlValues, LookAt:=xlWhole, MatchCase:=True)
Set EndRangeNRE = rngall.Find(What:="Recurring Costs", LookIn:=xlValues,LookAt:=xlWhole, MatchCase:=True)
Set StartRangeNRE = rngall.Find(What:="Non-Recurring Costs",LookIn:=xlValues, LookAt:=xlWhole, MatchCase:=True)
Set StartRangeRE = rngall.Find(What:="Recurring Costs", LookIn:=xlValues,LookAt:=xlWhole, MatchCase:=True)
Set looprng = Sheets("{Activity} 7300-1input template").Range(StartRangeNRE, EndRangeRE)
For Each Row In looprng
Cells(0, 4).Merge
Next Row
End Sub
This one gives me an error and I'm not sure how to specify to do each row, A:D merge and next row. Would it be a do loop? I'm very open to the easiest way to make this happen so suggestions are gladly welcomed (I'm not too experienced in coding so anything to help me learn!). Thanks!
maybe you're after this:
Option Explicit
Sub Merge()
Dim EndRangeRE As Range, StartRangeNRE As Range
Dim myRow As Range
With Sheets("{Activity} 7300-1input template")
With .UsedRange
Set EndRangeRE = .Find(What:="10. Other Costs", LookIn:=xlValues, LookAt:=xlWhole, MatchCase:=True)
Set StartRangeNRE = .Find(What:="Non-Recurring Costs", LookIn:=xlValues, LookAt:=xlWhole, MatchCase:=True)
End With
For Each myRow In .Range(StartRangeNRE, EndRangeRE).Rows
.Rows(myRow.row).Resize(, 4).Merge
Next
End With
End Sub
where I got rid of unused variables and use some With-End With block to reference multiple reference of the same object
This will merge A through D for 100 rows:
Sub ytrewq()
For i = 1 To 100
Range("A" & i & ":D" & i).MergeCells = True
Next i
End Sub
EDIT#1:
Sub ytrewq()
For i = 1 To Cells(Rows.Count, 1).End(xlUp).Row
Range("A" & i & ":D" & i).MergeCells = True
Next i
End Sub
Try This code :
Sub test()
'Get The Last non empty row
lastRow = ThisWorkbook.Sheets("YourSheetName").Cells(Rows.Count, 1).End(xlUp).Row
For i = 1 To lastRow
ThisWorkbook.Sheets("YourSheetName").Range("A" & i & ":D" & i).Merge
Next i
End Sub
The code below incoropates Merging cells in columns "A:D" in your looprng range.
Code
Option Explicit
Sub Merge()
Dim EndRangeRE As Range
Dim EndRangeNRE As Range
Dim rngall As Range
Dim StartRangeNRE As Range
Dim StartRangeRE As Range
Dim looprng As Range
' 2 added object variables
Dim Sht As Worksheet
Dim myRow As Range
' set your worksheet object, don't need to Activate it
Set Sht = ThisWorkbook.Sheets("{Activity} 7300-1input template")
Set rngall = Sht.UsedRange
Set EndRangeRE = rngall.Find(What:="10. Other Costs", LookIn:=xlValues, LookAt:=xlWhole, MatchCase:=True)
Set EndRangeNRE = rngall.Find(What:="Recurring Costs", LookIn:=xlValues, LookAt:=xlWhole, MatchCase:=True)
Set StartRangeNRE = rngall.Find(What:="Non-Recurring Costs", LookIn:=xlValues, LookAt:=xlWhole, MatchCase:=True)
Set StartRangeRE = rngall.Find(What:="Recurring Costs", LookIn:=xlValues, LookAt:=xlWhole, MatchCase:=True)
Set looprng = Sht.Range(StartRangeNRE, EndRangeRE)
' merge cells in columns "A:D" in your range
For Each myRow In looprng.Rows
Sht.Range(Sht.Range("A" & myRow.Row), Sht.Range("D" & myRow.Row)).Merge
Next myRow
End Sub
I've got a macro code to highlight cells in a sheet where the value comes from another sheet upon a button click on a separate sheet but it is returning value can't be found/none found when the value on both sheets is actually the same.
The value of the cell is a date value.
the 1st is the intended sheet and the 2nd one is the code
intended sheet to highlight cells
Sub HighlightSpecificValue()
Dim fnd As String, FirstFound As String
Dim FoundCell As Range, rng As Range
Dim myRange As Range, LastCell As Range
fnd = Range("H9").Value
Sheets("PO copy").Select
Set myRange = ActiveSheet.UsedRange
Set LastCell = myRange.Cells(myRange.Cells.Count)
Set FoundCell = myRange.Find(what:=fnd, after:=LastCell)
If Not FoundCell Is Nothing Then
FirstFound = FoundCell.Address
Else
GoTo NothingFound
End If
Set rng = FoundCell
Do Until FoundCell Is Nothing
Set FoundCell = myRange.FindNext(after:=FoundCell)
Set rng = Union(rng, FoundCell)
If FoundCell.Address = FirstFound Then Exit Do
Loop
rng.Interior.Color = RGB(255, 255, 0)
Exit Sub
NothingFound:
MsgBox "No cells containing: " & fnd & " were found in this worksheet"
End Sub
A couple of things need to be fixed:
You shouldn't try to compare a String to a cell containing a date - so it will be best to define fnd as a Variant
You are currently not specifying whether to look at values or formulas when doing the Find, or whether to look at part or the whole of the value - you should explicitly define those in order to avoid confusion due to Excel using whatever the user last used
I believe the following, slightly modified, code should work:
Sub HighlightSpecificValue()
Dim fnd As Variant, FirstFound As String
Dim FoundCell As Range, rng As Range
Dim myRange As Range, LastCell As Range
fnd = Range("H9").Value
Sheets("PO copy").Select
Set myRange = ActiveSheet.UsedRange
Set LastCell = myRange.Cells(myRange.Cells.Count)
Set FoundCell = myRange.Find(what:=fnd, _
after:=LastCell, _
LookIn:=xlValues, _
LookAt:=xlWhole)
If Not FoundCell Is Nothing Then
FirstFound = FoundCell.Address
Else
GoTo NothingFound
End If
Set rng = FoundCell
Do Until FoundCell Is Nothing
Set FoundCell = myRange.FindNext(after:=FoundCell)
Set rng = Union(rng, FoundCell)
If FoundCell.Address = FirstFound Then Exit Do
Loop
rng.Interior.Color = RGB(255, 255, 0)
Exit Sub
NothingFound:
MsgBox "No cells containing: " & fnd & " were found in this worksheet"
End Sub
The following code is similar to a Vlookup function. Was wondering why the same For Each...Next loop works when applied to Constants but not when it's applied to Formulas.
Thank you
Dim ws1 As Worksheet, ws2 As Worksheet
Dim SourceRange As Range, TargetRange As Range, TargetCell As Range,
Dim SourceCell As Range, SourceColumn As Range, TargetColumn As Range,
Dim TargetRangeConstant As Range, TargetRangeFormula As Range
On Error Resume Next
'set Worksheets and Ranges
Set ws1 = Worksheets("Sheet1")
Set ws2 = Worksheets("Sheet1")
Set SourceRange = ws1.Range("A:A")
Set TargetRange = ws2.Range("L:L")
Set SourceColumn = ws1.Range("C:C")
Set TargetColumn = ws2.Range("O:O")
Set TargetRangeConstant = TargetRange.SpecialCells(xlConstants)
Set TargetRangeFormula = TargetRange.SpecialCells(xlFormulas)
'For Constants
For Each TargetCell In TargetRangeConstant
Set SourceCell = SourceRange.Find(What:=TargetCell, LookIn:=xlValues, _
LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
If Not TargetCell Is Nothing Then
'"copies" cells in source to target
TargetCell.Offset(, TargetColumn.Column - TargetRange.Column) = SourceCell.Offset(, SourceColumn.Column - SourceRange.Column)
End If
Next
'Same Function but for Formulas
For Each TargetCell In TargetRangeFormula
Set SourceCell = SourceRange.Find(What:=TargetCell, LookIn:=xlFormulas, _
LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
If Not TargetCell Is Nothing Then
'"copies" cells in source to target
**TargetCell.Offset(, TargetColumn.Column - TargetRange.Column) = SourceCell.Offset(, SourceColumn.Column - SourceRange.Column)**
End If
Next
You should be using TargetCell.Formula in the second block. In my sample code below, A1 in Sheet1 has =SUM(B1:C1). In Sheet2, it is in D1. It returns the correct address.
Sub Test()
Dim TargetCell As Range
Dim TargetF, TestS As String
Set TargetCell = Sheet1.Range("A1")
TargetF = TargetCell.Formula
TestS = Sheet2.Cells.Find(What:=TargetF, LookIn:=xlFormulas).Address
MsgBox TestS 'Returns D1.
End Sub
Let us know if this works.