So first my disclaimer. While I have some programming background, im not proficient in VB scripting so I may need some hand holding on this but I am mighty grateful for any help you wonderful people can render.
Im creating a print button that will print a worksheet based on criteria that the user will type in. Well basically I need the script to check certain cells in a row and if there is data in those cells, move to the next line. Rinse and repeat until you get to a row with no data in those certain cells and then automatically print the correct number of pages based on the data. I hope that makes sense. I hope that makes sense.
I tried writing a piece of code to check certain columns and return the value when all of those columns are blank. Hope that helps you
Sub Printing()
Dim CheckCol1 As Integer, CheckCol2 As Integer
Dim rowCount As Integer, rowCount1 As Integer, rowCount2 As Integer, currentRow As Integer
Dim currentRowValue1 As String, currentRowValue2 As String
Dim found As String
found = "No"
CheckCol1 = 1 'column A has a value of 1
CheckCol2 = 2 'column B has a value of 2
rowCount1 = Cells(Rows.Count, CheckCol1).End(xlUp).Row
rowCount2 = Cells(Rows.Count, CheckCol2).End(xlUp).Row
rowCount = Application.Max(rowCount1, rowCount2)
' find the first blank cell on both the columns
For currentRow = 1 To rowCount
currentRowValue1 = Cells(currentRow, CheckCol1).Value
currentRowValue2 = Cells(currentRow, CheckCol2).Value
If (IsEmpty(currentRowValue1) Or currentRowValue1 = "") And (IsEmpty(currentRowValue2) Or currentRowValue2 = "") Then
MsgBox ("No data on Column A and B in row" & currentRow)
found = "Yes"
End If
Next
If found = "No" Then ' This will return rowcount+1 when the columns have values throughout the range
MsgBox ("No data on Column A and B in row" & rowCount + 1)
End If
End Sub
Note:- You can increase the number of columns to be checked by adding few variables. You can try Adding third column by adding Checkcol3, rowcount3, currentrowvalue3 and adding one more condition to the if clause
Related
I apologize, this is my first crack at Excel VBA so excuse my lack of knowledge!
So I have a list of (currently) 3 names to assign to the days in column A in a repeating order in Excel.
Currently my VBA code allows it to populate the selected cells with the names in a repeating pattern (this part is good), however there are two pieces I need help with.
1- with current code, once it reaches the bottom of the names it checks for the blank box that would end that list and starts over at the tops as directed but it puts a blank cell first (see screenshot). How can I have it put next name without adding blank cell first?
2- I want to be able to (once this gets going)select the entire D column through what dates need to be filled and:
-check the lowest non blank box
-match to list and set the
counter to name below that so
it continues the name order
from the last person who was
assigned
This is code I have now:
Sub EXAMPLE()
Dim count As Integer
count = 0
For Each c In Selection
c.Value = Range("X1").Offset(count, 0).Value
If c.Value = "" Then count = -1 And c.Value = Range("x1").Offset(count, 0).Value
count = count + 1
Next c
End Sub
Sorry I know that was long, I hope this makes sense.
I think it's worth reading about arrays, as this task is ideally suited to their use. Your best bet would be to read the names into an array and then build a recurring array whose dimension is equal to the number of rows in your dates column (or selection, or however you want to define the size of the output range).
Code would look a little like this:
Dim v As Variant
Dim people() As Variant, output() As Variant
Dim rowCount As Long, i As Long, j As Long
Dim endRange As Range
'Read the list of names into an array.
'This just takes all data in column "X" -> amend as desired
With Sheet1
Set endRange = .Cells(.Rows.Count, "X").End(xlUp)
v = .Range(.Cells(1, "X"), endRange).Value
End With
'Sense check on the names data.
If IsEmpty(v) Then
MsgBox "No names in Column ""X"""
Exit Sub
End If
If Not IsArray(v) Then
ReDim people(1 To 1, 1 To 1)
people(1, 1) = v
Else
people = v
End If
'Acquire the number of rows for repeating list of names.
'This just takes all data in column "A" -> amend as desired
With Sheet1
Set endRange = .Cells(.Rows.Count, "A").End(xlUp)
rowCount = .Range(.Cells(3, "A"), endRange).Rows.Count
End With
'Sense check date data.
If endRange.Row < 3 Then
MsgBox "No dates in Column ""A"""
Exit Sub
End If
'Make a recurring array.
ReDim output(1 To rowCount, 1 To 1)
i = 1
Do While i <= rowCount
For j = 1 To UBound(people, 1)
output(i, 1) = people(j, 1)
i = i + 1
If i > rowCount Then Exit Do
Next
Loop
'Write the output to column "D"
Sheet1.Range("D3").Resize(UBound(output, 1)).Value = output
I have been trying to find something that can help me online but no luck. I am trying to compare a value in column A with a value in Cell E1 and if match I want to put an X in column B next to the match in Column A.
here is my code I go so far:
Option Explicit
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim a As Integer
Dim i As Integer
Dim x As Range
Dim y As Range
a = Worksheets("Sheet1").Cells(Rows.Count, 1).End(xlUp).Row
i = Worksheets("Sheet1").Range("E1")
x = Worksheets("Sheet1").Range("B1:a")
y = Worksheets("Sheet1").Range("A1:a")
'For Each cell In y
'if y = i then
'print "X" in column B next to the value
'MsgBox (i)
End Sub
thanks for your help in advance
Dan
There are a few things here that are worth mentioning. When you want to specify a range using .Range you have to specify the columns on both sides of the : ; furthermore, it takes a string. This means that what you're passing is "B1:a" which doesn't make sense to the computer because it doesn't know you want it to use the value of a instead of the letter. You need to pass "B1:B" & a to the .Range. What this does is concatenate the value you found in the variable a to the string so it appears as one string to the computer.
I personally think it's easier to take all of the values as a column vector instead of dimming the x's as a range because it makes the iteration a little easier. Instead of keeping track of what row I'm on, Counter will always tell me where I am since I'm just moving down a single column. As an added bonus, this reduces the times you access the worksheet which helps speed up your macro.
Although it's commented out, it's worth noting that the loop at the bottom of your sub wouldn't work because you haven't properly closed off the if or the for.
I'm not sure what you intended this for, but it's never a bad idea to use meaningful names so you can look back on your code and figure it out without too much effort. For example, I've renamed your a variable to lastrow which at a glance describes what value it stores.
Below your code that I've altered
Option Explicit
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim lastrow As Long
Dim Criteria As Long
Dim x() As Variant
Dim Counter As Long
lastrow = Worksheets("Sheet1").Cells(Rows.Count, 1).End(xlUp).Row
Criteria = Worksheets("Sheet1").Range("E1").Value
x = Worksheets("Sheet1").Range("B1:B" & lastrow).value
For Counter = 1 To UBound(x)
If x(Counter,1) = Criteria Then
Worksheets("Sheet1").Cells(Counter, "B").Value = "X"
End If
Next Counter
MsgBox (Criteria)
End Sub
I little bit different approach. This find the last row in column A.
I also included if you want to match by wildcard, i.e. you want to find 45 in 645.
Sub Worksheet_SelectionChange()
Dim lrow As Integer
Dim a As Integer
Dim i As String
Dim Val As String
lrow = Worksheets("Sheet1").Cells(Rows.Count, "A").End(xlUp).Row 'Find last row
i = Worksheets("Sheet1").Range("E1") 'Set cell where compare value is
For a = 1 To lrow 'Loop from row 1 to last row in column A
Val = Cells(a, "A").Value 'Set value to compare in Column A
'If Val Like "*" & i & "*" Then 'Use this if you want to find 45 in 645, so wildcard
If Val = i Then 'Exact match
Cells(a, "B").Value = "X" 'Put X in column B
End If
Next a
MsgBox "Match Criteria: " & (i)
End Sub
I would like to ask your help for this task.
The excel sheet contains duplicated items in ColumnA. I want to combine these duplicates into one row. Please see the picture.
As the actual picture shows, there are three As in ColumnA. For every A there are some cells from ColumnB. Lets say those are the values to A. The values from every rows are marked with different colors seperately.
I want to combine A's values into one row, as the target picture shows.
The excel sheet was pre-sorted, so that all duplicates from ColumnA always appear together.
Please be noticed there are also items without duplicates: There is only one E in ColumnA. No transpose is required for this row.
Please also be noticed that there could be more duplicted items in ColumnA. E.g. 10x Ts, or 30x Ks.
To make the task easier, it is no need to delete the blank rows after the transformation.
The colors are used only to show the problem, there is no color in the excel sheet.
So far for this task.
Actually I asked a similar question before: Excel VBA: How to transform this kind of cells?
In the link there are some very good codes, but sadly I am not capable to rewrite the code for this task.
So please help me~
But please dont forget to have a happy weekend~
Thanks!
Try the code below ("bonus" feature, also removes the empty rows).
As you wrote in your post, the data is sorted according to Column A, and there are no empty rows in your data.
Sub TransposeDup()
Dim LastCol, LastColCpy As Long
Dim lrow As Long
lrow = 1
While Cells(lrow, 1) <> ""
If Cells(lrow, 1) = Cells(lrow + 1, 1) Then
LastCol = Cells(lrow, Columns.Count).End(xlToLeft).Column
LastColCpy = Cells(lrow + 1, Columns.Count).End(xlToLeft).Column
Range(Cells(lrow + 1, 2), Cells(lrow + 1, LastColCpy)).Copy Destination:=Cells(lrow, LastCol + 1)
Rows(lrow + 1).EntireRow.Delete
Else
lrow = lrow + 1
End If
Wend
End Sub
Something like the following should get you in the right direction. This doesn't copy formats, but it gets the values. You could tweak it to get where you need to go though:
Sub dedup_and_concat()
Dim intWriteCol As Integer
Dim intReadCol As Integer
Dim intWriteRow As Integer
Dim intReadRow As Integer
Dim intStartRow As Integer
Dim intEndRow As Integer
Dim strPrevRowValue As String
'Start and end rows:
intStartRow = 1
intEndRow = 8
'initial values:
intWriteRow = 1
'Loop from your start row to your end row
For intReadRow = intStartRow To intEndRow 'beginning and ending rows
intReadCol = 2
'If we are at the first row, then just capture values
'Also if this is a new value, then reset all of the write variables
If intReadRow = intStartRow Or Sheet1.Cells(intReadRow, 1).Value <> Sheet1.Cells(intWriteRow, 1).Value Then
'set the row and initial column we are writing to
intWriteRow = intReadRow
intWriteCol = Sheet1.Cells(intReadRow, 1).End(xlToRight).Column() + 1
Else
'We are on a row that needs to be concatenated and deleted
'So loop through all of the columns to get their values
'And write their values to the read row and read col
Do Until Sheet1.Cells(intReadRow, intReadCol).Value = ""
Sheet1.Cells(intWriteRow, intWriteCol).Value = Sheet1.Cells(intReadRow, intReadCol).Value
'increment read and write columns
intWriteCol = intWriteCol + 1
intReadCol = intReadCol + 1
Loop
'remove this rows values
Sheet1.Rows(intReadRow).ClearContents
End If
Next intReadRow
End Sub
I have a list that contains Employee ID in Col A, First Name in Col B, Last Name in Col C. I am needing to write a macro that gives a userform to input First and Last Name and from there it will put the proper Employee ID into the first unused cell in Col E and then loop back to the userform.
I already know how to build the Userform and will have two buttons on it one that reads "Next" and one that reads "End". The "Next" button will loop the Userform and the "End" will just close the Userform.
Plan on leaving the Userform named Userform1 and naming the input boxes as "FirstName" and "LastName". So I know that to reference these from the macro I would call for Userform1.FirstName.Value or Userform1.LastName.Value depending on which part I need at the moment.
The part I am not sure on is how to the matching of two variables and then looking to the left for the ID. I can move the ID Col to be after the name Cols if that helps but I am still not sure how to write so that both names must match.
As for error trapping I planned on having a MsgBox state "There are no matching entries." If the person does not exist in the list. However I am unsure of how to handle the super unlikely but possible situation of if two people on the list have the same name. So any suggestions for this would be greatly appreciated.
I am using Excel 2013.
Try this for the next button
Private Sub NextButton_Click()
Dim emptyRow As Long
Dim matchFound As Boolean
Dim matchCount As Long
Dim matchRow As Long
Dim i As Long
'Determine the first empty cell in column E
If Cells(1, 5).Value = "" Then
emptyRow = 1
Else
emptyRow = Cells(Columns(5).Rows.Count, 5).End(xlUp).Row + 1
End If
matchFound = False
matchCount = 0
matchRow = 0
'Loop through all of rows that have an employee id
For i = 1 To Cells(Columns(1).Rows.Count, 1).End(xlUp).Row
If (UCase(FirstName.Value) = UCase(Cells(i, 2).Value)) And (UCase(LastName.Value) = UCase(Cells(i, 3).Value)) Then
matchCount = matchCount + 1
matchRow = i
matchFound = True
End If
Next
'Alert user of any errors
If matchFound = False Then
MsgBox ("There are no matching entries")
ElseIf matchCount > 1 Then
MsgBox ("There were multiple matches")
Else
'If there are no errors add employee id to the list
Cells(emptyRow, 5).Value = Cells(matchRow, 1).Value
emptyRow = emptyRow + 1
End If
'Clear the userform
FirstName.Text = ""
LastName.Text = ""
End Sub
I'm not sure what the best course of action to take if there are multiple matches, so for now I just included a message to alert the sure. It wouldn't be hard to change the code to track each of the matched rows instead of just the last one.
I would suggest using vlookup, as it's basically designed around your problem. It takes an input, finds it in one column, then outputs the same row in a different column. It shouldn't be difficult to make the output dependent on two vlookups matching to the same output.
http://www.howtogeek.com/howto/13780/using-vlookup-in-excel/
I am looking a way of creating excel vba for calculating average, depends upon another cell
In above picture, I want calculate average of those cell in column C, where A column has the name on it.In this case, average of cells C6,C7,C8 (and skip C9 and C10)because Name column (Column A) has data in only A6,A7,A8. While calculating I need to count 0 as well.
not getting a way to create formula, tried with averageif, but that only check for a specific data
can somebody give a hint to form the this vba function
Try this:
=(SUMPRODUCT(--(ISBLANK(A6:A10)=FALSE),--(C6:C10)))/COUNTA(A6:A10)
Maybe:
=AVERAGEIF(A6:A10,"<>",C6:C10)
In VBA you can try something like this:
Dim lastRowOfColA As Long
lastRowOfColA = ActiveSheet.Cells(Rows.Count, "A").End(xlUp).Row 'Get last row of column A containing data
Dim rowCount As Long 'Number of rows containing data in column C
Dim sum As Long 'The sum of the values in column C
Dim i As Long
For i = 6 To lastRowOfColA
Dim valOfColA As String
valOfColA = Cells(i, 1).Value
Dim valOfColC As String
If valOfColA <> "" Then
valOfColC = Cells(i, 3).Value
If valOfColC <> "" Then
rowCount = rowCount + 1
sum = sum + valOfColC
End If
End If
Next
If rowCount > 0 Then
MsgBox ("Average: " & (sum / rowCount))
Else
MsgBox ("No rows with data found!")
End If
Of course you have to put that in a function and use parameters instead of the hard coded values above.