I currently have a code that finds the first empty cell in a specific column and saves the result of a "SumIfs" calculation into that cell. It runs for multiple columns on multiple criteria. The example below is one instance where I search for the criteria "R" and "ECHO", sum the corresponding values from column 16, and place the result in column "C" of another worksheet:
Sub SumIfs()
Dim ws2 As Worksheet: Set ws2 = ThisWorkbook.Sheets("previous_day_split")
Worksheets("daily_balance").Activate
Range("C" & Rows.Count).End(xlUp).Offset(1, 0).Value = _
Application.SumIfs(ws2.Columns(16), ws2.Columns(15), "R", ws2.Columns(20), "ECHO")
End Sub
It works great, but now instead of just placing the result in the first empty cell of column "C", I want to find a way to designate a row (not always going to be the first empty one) based on specific dates in the first column of "daily_balance".
In short, for example, I want the code to essentially search for a date (say 11/2/2015) in the first column of the worksheet "daily_balance", designate that row as the row to dump the values into, run the SumIfs function in "ws2", and place the results in column "C" for the row containing 11/2/2015.
Any suggestions or ideas on the best way to designate a row based on criteria?
You can easily look for a specific value in a column using Do While loop:
i = 0
Do While Cells(i, "A") <> {lookup_value} And Cells(i, "A") <> ""
i = i + 1
loop
'Check that {i} holds row number for our lookup value and not for an empty one
if Cells(i, "A") = {lookup_value} then
'Do your calculations here
'And then use {i} as row number to save your result.
end if
So {lookup_value} is a constant or variable holding the date you are looking for. In case your dates are not well formated you might need to use CDate() to bring your lookup_value and cell value to the same format, meaning that instead of:
Do While Cells(i, "A") <> {lookup_value} And Cells(i, "A") <> ""
you should use:
Do While CDate(Cells(i, "A")) <> CDate({lookup_value}) And Cells(i, "A") <> ""
Good luck with that, and feel free to ask for more details.
Related
I have a task to complete where I want to create a table using values from one sheet based on condition using VBA and ActiveX Button.
This are table entries from which I need to pick values based on condition Cell(J, 62).values = "Not Compliant" or "Partially Compliant".
To understand it better, where ever in column J the value is "Not Compliant or Partially Compliant" for rows I want certain details to be included in a new sheet as dynamic entries. Below is the format of the new table that I would like to create. I have mentioned the column names that I want in the new table.
Column C | Serial No. (Values based number of entries) | Column L | Column M
The number of values may depend on the number of Not Compliant and Partially compliant numbers.
Can anyone help me getting a code for this. I am unable to write a logic for this condition.
Assuming you have 2 Sheets in your Workbook where the first sheet is your Table and the second sheet is the destination for the items where the data is not compliant:
Option Explicit
Sub RunComplianceCheck()
Dim c As Range 'Each cell that the loop will look at to determine Compliance Status
Dim rng As Range 'The range of all the entries in the table
Dim totNC 'The total Non or Partially Compliance entries on the second tab
Sheet2.Activate
Sheet2.Range(Cells(2, 1), Cells(2, 1).SpecialCells(xlLastCell)).ClearContents 'Clear all previous data
Sheet1.Activate
With Sheet1
Set rng = .Range(Cells(2, 10), _
Cells(Application.WorksheetFunction.CountA(.Range("J:J")), 10)) 'Set the range of all the entries in the table
End With
For Each c In rng 'Loop through each entry
If c.Value = "Not Compliant" Or c.Value = "Partially Compliant" Then 'If Not Compliant or Partially Complaint execute the below
With Sheet2
totNC = Application.WorksheetFunction.CountA(.Range("A:A")) + 1 'Get the first empty row on the second Sheet of Non or Partially Compliant data
.Cells(totNC, 1).Value = c.Offset(0, -7).Value 'Get data in column C
.Cells(totNC, 2).Value = c.Offset(0, -9).Value 'Get data in column A
.Cells(totNC, 3).Value = c.Offset(0, 2).Value 'Get data in column L
.Cells(totNC, 4).Value = c.Offset(0, 3).Value 'Get data in column M
End With
End If
Next c 'Next cell
Sheet2.Activate
End Sub
This sub will loop through each row of your data set and find the entries marked Non-Compliant or Partially Compliant, then will grab the Question(s), Serial No., Finding / Gap Description, and Finding Rating data for each one (as requested) and place them in the second sheet.
I have a project that I am working on where multiple conditions are checked across all rows and many columns. The issue is that columns are added/removed from the sheet, and, at present, that results in all of my cell(row,column) references being off + outputting incorrect information. I'm wondering if there's a way to make my column references more robust so that they automatically find the correct headers and use them when checking? Would a solution to this problem be able to account for multiple columns containing the exact same header text?
Basically:
No blank columns
Column headers have repeats (e.g., Column 1 header: "Financials"; Column 15 header: "Financials")
Columns are shifting right and left based on adding/removing columns from sheet
Please find a short sample of my current code below with notes:
Dim i As Integer
Dim lastRow As Long
Dim lastCol As Long
lastRow = Range("A1").End(xlDown).Row
lastCol = Cells(1, Columns.Count).End(xlToLeft).Column
For i = 2 To lastRow
Select Case Cells(i, 14).Value
Case Is = "Yes"
Select Case True
Case Cells(i, 63).Value = 6 And _
(IsEmpty(Cells(i, 77)) Or IsEmpty(Cells(i, 93)) Or IsEmpty(Cells(i, 109)) Or _
IsEmpty(Cells(i, 125)) Or IsEmpty(Cells(i, 141)) Or IsEmpty(Cells(i, 157)))
Cells(i, 174).Value = "True" '^THESE CELL VALUES ALL HAVE THE SAME COLUMN HEADER TITLE
If the table is consistent - starting at A1 and occupying a contiguous block - then Range("A1").CurrentRegion will reference the table.
You can then use .CreateNames to name the columns (that is, using Named Ranges) according to their headings.
Dim rngTable As Range
Dim rng As Range
Set rngTable = Range("A1").CurrentRegion
rngTable.CreateNames True, False, False, False
' that is, based on the first row headings
Range("Salary").Select 'prove it works
'if necessary, iterate the cells of the column,
For Each rng In Range("Salary")
rng.Value = rng.Value + 10
Next 'rng
If a column heading is duplicated ("Financial"), though, then you'll be asked to confirm and the second occurrence will overrule the first. (Or you could say "No" and the first occurrence will be named.) In which case, it is preferable that you first correct these duplicate headings.
Correcting the duplicate headings is not necessarily straight forward, but something that you should resolve anyway. If it is a specific word "Financials" (or words) that could be duplicated then this makes the task easier. You could count how many occurrences there are, and correct the second, etc., to "Financials2".
One easy way to to assign a Name to the column. Say column N has the header "Payments". First assign the Name "Payments" to that column:
Then in VBA we can code like:
Sub dural()
Dim rng As Range, colly As Long
Set rng = Range("Payments")
colly = rng.Column
For i = 2 To 100
If Cells(i, colly) = "whatever" Then
MsgBox "Help"
End If
Next i
End Sub
The code will continue to work even if you add/remove columns beforre column N.
I am trying to write a snippet of code to run through multiple worksheets and, if the value in column "h" is not empty, copy each sheet row-by-row to a master summary sheet. My problem is that every cell in column "h" contains a CONCATENATE formula, but of course if the rest of the row is empty then the CONCATENATE returns an empty or 0 value. For some reason the following code is failing to ignore these rows. (Note: w is the object representing the current worksheet, and dest is the object representing the destination worksheet where rows will be copied to.)
Last = w.Cells(Rows.Count, "h").End(xlUp).Row
For a = 2 To Last Step 1
If w.Cells(a, "h").Text <> "" Or w.Cells(a, "h").Text <> "0" Then
d = dest.Cells(Rows.Count, "h").End(xlUp).Row + 1
w.Cells(a, "h").EntireRow.Copy dest.Cells(d, 1)
End If
Try If w.Cells(a, "h").value <> ""
This process is being used for QC purposes. I have a spreadsheet that highlights certain cells that are wrong based off of their values and the validation rules we have in place. I was wonder if there was a way to return the column names of each cell that is colored into column A for each row? So for example if D2, F2, and G2 are wrong it would put all of those column headers in A2 to specify what exactly is wrong. I know it gets a bit more complicated trying to automate stuff with cell colors and I am not experienced in VBA which I'm assuming this will need. Is this possible to do, if so what would be the proper route to take? The data runs from column A to column BS, and the row numbers may differ, so if it could run up to row 1,000 that would be great. Attached is what the data looks like that I am working with.
The red means something is wrong in that row, and the orange cell is the color indicating that it is a wrong value
Yes, it is possible to do. Here is some snippets of code I pulled together to help get you started.
Lastrow = Cells(Rows.count, "A").End(xlUp).Row 'Get last row
With ActiveSheet
Lastcol = .Cells(1, .Columns.count).End(xlToLeft).Column 'Get last col
End With
For x = 1 To Lastcol 'Iterate Col
For i = 1 To Lastrow 'Iterate Row
'if red....
If Cells(i, x).Selection.Interior.Color = 255 then
'Move name to Cell A and append off of old name(s).
Cells(i, "A") = Cells(i, "A") & ", " & Cells(i, x)
End If
Next i 'next row
Next x 'next col
I am a bit new to using VBA. I have a data table, that pulls data in from one of the programs I use, and is filtered through Microsoft Query. There is one column I can't sort, so I need to use an if and statement to remove unwanted data. I came up with this if statement, which highlights the rows I want to delete, but I don't know how to put it into VBA.
=IF(L5="Program",L6<>"lathe"),"2","")
Basically I want the VBA to look at Column L:L. If the cell=program, and the cell below does not equal lathe I want the row above to be deleted. If the cell doesn't equal program continue looking until the end of the data.
In VBA, you'd use the IF ... And ... Then structure, thus:
If Range("L5")="Program" And Range("L6") <> "lathe" Then
'Do something
End If
You'll probably want to replace the Range(...) statements with a range variable of some sort to store the cells you're really interested in, but that should give you an idea of the structure you're looking for.
EDITED TO ADD:
Loop through all of column L like this:
Dim rngCheck as Range
Dim rngCell as Range
Set rngCheck = Range("L1", "L" & Rows.Count - 1)
For each rngCell in rngCheck
If rngCell.value = "Program" And rngCell.offset(1,0).value <> "lathe" then
rngCell.offset(-1,0).EntireRow.Delete
End if
Next rngCell
This:
Creates a range to look at (column L)
Loops through all cells in that column (the For each loop)
Runs our IF logic and
...deletes the entire row if the logic is met.
Here is your idea behind it. you will just need to fix the format as you'd like.
If cells(5, "L") = "Program" AND cells(6, "L") <> "Lathe" Then
cells (6, "M") = 2
Else
cells (6, "M") = ""
EndIf
The best is to loop on column L. Imagine your data is from row 3 to 150
for i = 3 to 150
if lcase(range("L"&i).value) = "program" and lcase(range("L"&i+1).value) <> "lathe" then
rows(i).entirerow.delete
end if
next i