VBA, syntax, group range of cells together for common variable - excel

Im working on a little script (below). The script iterates through rows on a data set and places either a 1 or 0 in a cell based on some contingencies of 2 select case statements. It works perfect, but I want to know if there's a way to group the range of cells together that are getting a 0 placed within them.
Sub compVal()
Dim WB As Workbook 'an object of type workbook
Dim WS1 As Worksheet ' objects of type worksheet
Set WB = ActiveWorkbook ' reference WB to the current Workbook
Set WS1 = Worksheets("Sheet1") 'Reference to Sheet 1 of the current workbook
'loop through sheet1's rows
Dim i As Integer
For i = 2 To WS1.UsedRange.Rows.Count
Select Case WS1.Cells(i, 1).Value 'first cell from row i
Case "Target"
Select Case WS1.Cells(i, 2).Value
Case 1
WS1.Cells(i, 3).Value = 1
WS1.Cells(i, 4).Value = 0
WS1.Cells(i, 5).Value = 0
WS1.Cells(i, 6).Value = 0
Case 2
WS1.Cells(i, 3).Value = 0
WS1.Cells(i, 4).Value = 0
WS1.Cells(i, 5).Value = 1
WS1.Cells(i, 6).Value = 0
End Select
Case "NonTarget"
Select Case WS1.Cells(i, 2).Value
Case 1
WS1.Cells(i, 3).Value = 0
WS1.Cells(i, 4).Value = 1
WS1.Cells(i, 5).Value = 0
WS1.Cells(i, 6).Value = 0
Case 2
WS1.Cells(i, 3).Value = 0
WS1.Cells(i, 4).Value = 0
WS1.Cells(i, 5).Value = 0
WS1.Cells(i, 6).Value = 1
End Select
End Select
Next i
End Sub

This is a great example of code re-use:
Sub compVal()
Dim WB As Workbook 'an object of type workbook
Dim WS1 As Worksheet ' objects of type worksheet
Set WB = ActiveWorkbook ' reference WB to the current Workbook
Set WS1 = Worksheets("Sheet1") 'Reference to Sheet 1 of the current workbook
'loop through sheet1's rows
Dim i As Long ' USE LONG FOR CELL REFERENCES, THERE ARE A LOT OF ROWS POSSIBLE : )
For i = 2 To WS1.UsedRange.Rows.Count
Select Case WS1.Cells(i, 1).Value 'first cell from row i
Case "Target"
Select Case WS1.Cells(i, 2).Value
Case 1
AddColumns WS1, i, 1, 0, 0, 0
Case 2
AddColumns WS1, i, 0, 0, 1, 0
End Select
Case "NonTarget"
Select Case WS1.Cells(i, 2).Value
Case 1
AddColumns WS1, i, 0, 1, 0, 0
Case 2
AddColumns WS1, i, 0, 0, 0, 1
End Select
End Select
Next i
End Sub
Sub AddColumns(WS As Worksheet, i As Long, c As Variant, d As Variant, e As Variant, f As Variant)
WS.Cells(i, 3).Resize(1, 4).Value = Array(c, d, e, f)
End Sub
There are other efficiencies that could be introduced, such as replacing the four arguments c,d,e and f with a single integer where
0 = 0,0,0,0
1 = 1,0,0,0
2 = 0,1,0,0
...
15 = 1,1,1,1

Related

Comparing columns and transferring data

I am comparing two sheets and their columns. My code runs. Problem is it compares most of the values and leaves some values though they are the same.
Sub Peformance()
Dim k As Integer
Dim i As Integer
Dim j As Integer
For i = 1 To 138
If (ActiveWorkbook.Worksheets("report").Cells(i, 6).Value = "course-1") Then
For j = 1 To 138
If (ActiveWorkbook.Worksheets("report").Cells(i, 1).Value = Cells(j, 1)) Then
Cells(j, 4).Value = (ActiveWorkbook.Worksheets("report").Cells(i, 12).Value) / 100
Cells(j, 5).Value = (ActiveWorkbook.Worksheets("report").Cells(i, 20).Value) / 100
Cells(j, 6).Value = (ActiveWorkbook.Worksheets("report").Cells(i, 13).Value)
End If
Next j
End If
Next i
For k = 1 To 138
If (IsEmpty(Cells(k, 4).Value)) Then
Cells(k, 4).Value = 0
Cells(k, 5).Value = 0
End If
If (IsEmpty(Cells(k, 6).Value)) Then
Cells(k, 6).Value = 0
End If
End Sub
In one file (sheet-2) I have students courses like course-1, course-2, course-3 etc.
In the other file (sheet-1) I have students names.
After comparing names (Column-1 of sheet-2 and sheet-1) I have to copy the performance from sheet-2 to sheet-1.
It runs but is not showing output for some students whose names are same.
Also how can I add the feature of case sensitive?
Sample Data
Sheet2:
Name
Email
External
Course
Course-ID
Course-Slug
Work-Percentage
A
a#gmail.com
12
A
course
course-1
63%
B
b#gmail.com
13
A
course
course-1
19%
Sheet1:
Name
Work-Percentage
A
B
So sheet1 column Work-Percentage will copy data from Work-Percentage column after comparing the name and course-Slug from sheet-2
Double For...Next
Adjust the name of the Destination Worksheet (dws) because I named it Course-1.
StrComp is taking care of the case-sensitivity issues.
This is just a quick fix for you to learn (understand). Otherwise, the efficiency can vastly be improved.
Not tested.
The Code
Option Explicit
Sub Peformance()
' Constants
Const sFirstRow As Long = 2
Const dFirstRow As Long = 2
' Workbook
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
' Source
Dim sws As Worksheet: Set sws = wb.Worksheets("Report")
Dim sLastRow As Long: sLastRow = sws.Cells(sws.Rows.Count, 1).End(xlUp).Row
Dim k As Long
' Destination
Dim dws As Worksheet: Set dws = wb.Worksheets("Course-1")
Dim dLastRow As Long: dLastRow = dws.Cells(dws.Rows.Count, 1).End(xlUp).Row
Dim i As Long
' Loop
For i = dFirstRow To dLastRow
For k = sFirstRow To sLastRow
If StrComp(sws.Cells(k, 6).Value, "course-1", vbTextCompare) = 0 _
And StrComp(dws.Cells(i, 1).Value, sws.Cells(k, 1).Value, _
vbTextCompare) = 0 Then
' Student was found in Source Worksheet.
dws.Cells(i, 4).Value = sws.Cells(k, 12).Value / 100
dws.Cells(i, 5).Value = sws.Cells(k, 20).Value / 100
dws.Cells(i, 6).Value = sws.Cells(k, 13).Value
Exit For ' Student was found, no need to loop any longer.
End If
Next k
If k > sLastRow Then
' Student wasn't found in Source Worksheet.
If IsEmpty(dws.Cells(i, 4)) Then
If IsEmpty(dws.Cells(i, 6)) Then
dws.Cells(i, 4).Resize(3).Value = 0
Else
dws.Cells(i, 4).Resize(2).Value = 0
End If
End If
End If
Next i
End Sub

Run Time Error: 13 showing while looking through #N/A string

I'm trying to run the below code to find whether the A column has keyword "SUP ID" or not. Any instance of SUP ID would be updated with number 1 on adjacent column and rest all would go as 0. However while finding the #N/A word, getting error Run-Time Error '13': Type Mismatch
Sub m()
For i = 2 To 10
If Cells(i, 1).Value = "SUP ID" Then
Cells(i, 2).Value = 1
Else
Cells(i, 2).Value = 0
End If
Next i
End Sub
You will need to check for the error before the existing if:
Sub m()
With ActiveSheet 'Better to use actual sheet: WorkSheets("Sheet1")
'load with all `0`
.range("B2:B10").Value = 0
For i = 2 To 10
If Not IsError(.Cells(i, 1)) Then
If .Cells(i, 1).Value = "SUP ID" Then
.Cells(i, 2).Value = 1
End If
End If
Next i
End with
End Sub
With only 9 cells to check the above will run quickly, but as the range increases the number of times that vba references the worksheet will slow it down.
You can use Arrays to speed it up.
Sub m()
With ActiveSheet 'Better to use actual sheet: WorkSheets("Sheet1")
Dim inputArr() As Variant
inputArr = .Range("A2:A10").Value
'Default of Integer is `0`
Dim outputArr() As Integer
ReDim outputArr(1 To UBound(inputArr, 1), 1 To 1) As Integer
For i = LBound(inputArr, 1) To UBound(inputArr, 1)
If Not IsError(inputArr(i, 1)) Then
If inputArr(i, 1) = "SUP ID" Then
outputArr(i, 1) = 1
End If
End If
Next i
.Range("B2").Resize(UBound(inputArr, 1)).Value = outputArr
End With
End Sub

How to find a value in column and paste ranges from other worksheets into its adjacent columns

The end goal for my project is that the user will be able to select a value from a ComboBox to fill out a report on a Summary Tab. The report will consist of 3, 3 cell ranges (divided into 3 1x3 ranges on 3 separate worksheets).
I want to find the row with the value the user selected in the ComboBox and then set the 9 cells to the right of that value equal to the values in the range mentioned previously.
I've tried a couple of different ways of doing this, but I'll include the code I most recently worked on below:
Private Sub OKButton1_Click()
Dim userValue, rangeOne, rangeTwo, rangeThree
Dim i As Long
i = 4
userValue = ComboBox1.Value
Set rangeOne = Sheets("Sheet2").Range(Range("F23:H23")
Set rangeTwo = Sheets("Sheet3").Range("F90:H90")
Set rangeThree = Sheets("Sheet4").Range("F17:H17")
While Sheets("Reports").Range(cells(i,1)).Value <> ""
If Sheets("Reports").Range(cells(i, "A")).Value = "userValue" Then
Set Sheets("Reports").Range(Cells(i, "B:E")) = rangeOne
Set Sheets("Reports").Range(Cells(i, "F:I")) = rangeOne
Set Sheets("Reports").Range(Cells(i, "J:M")) = rangeOne
End If
i = i + 1
Wend
Unload UserForm2
End Sub
Any Ideas on how I can improve this or get it working? Currently getting 1004 errors.
Two words of advice when working with excel:
always make variables for each sheet/book you need to work with
Avoid using ranges and objects if you can. It is much easier to iterate over individual cells using an array and a for loop like I did below.
I was a bit confused on exactly what you needed done, so you will need to modify this slightly to fit your ranges/where you want the data to go. If you are confused or need further assistance let me know and I'll update this.
Dim userValue
Dim xrow As Long, ws1 As Worksheet, ws2 As Worksheet, ws3 as Worksheet, ws4 as Worksheet
Dim arrData() as variant
set ws1 = Worksheets("Report")
set ws2 = Worksheets("Sheet2")
set ws3 = Worksheets("Sheet3")
set ws4 = Worksheets("Sheet4")
userValue = ComboBox1.Value
xrow = 1
ws2.activate
'the InStr function checks if the first condition contains the second, and when it does, it returns 1, which in turn triggers the if statement
for x = 1 To ws2.Cells(rows.count, 1).end(xlup).row
if InStr(1, Cells(x, 1), userValue) > 0 Then
arrData(0) = ws2.Cells(x, 2).value
arrData(1) = ws2.Cells(x, 3).value
arrData(2) = ws2.Cells(x, 4).value
else:
end if
next x
ws3.activate
for x = 1 To ws3.Cells(rows.count, 1).end(xlup).row
if InStr(1, Cells(x, 1), userValue) > 0 Then
arrData(3) = ws3.Cells(x, 2).value
arrData(4) = ws3.Cells(x, 3).value
arrData(5) = ws3.Cells(x, 4).value
else:
end if
next x
ws4.activate
for x = 1 To ws4.Cells(rows.count, 1).end(xlup).row
if InStr(1, Cells(x, 1), userValue) > 0 Then
arrData(6) = ws4.Cells(x, 2).value
arrData(7) = ws4.Cells(x, 3).value
arrData(8) = ws4.Cells(x, 4).value
else:
end if
next x
ws1.activate
ws1.Cells(xrow, 1) = userValue
for y = 0 To 8
ws1.Cells(xrow, y+1).value = arrData(y)
next y
xrow = xrow + 1
For x = 1 To ws1.Cells(Rows.Count, 1).End(xlUp).Row
If InStr(1, Cells(x, 1), UserValue) > 0 Then
ws1.Cells(x, 2) = ws2.Cells(23, 6).Value
ws1.Cells(x, 3) = ws2.Cells(23, 7).Value
ws1.Cells(x, 4) = ws2.Cells(23, 8).Value
ws1.Cells(x, 6) = ws3.Cells(90, 6).Value
ws1.Cells(x, 7) = ws3.Cells(90, 7).Value
ws1.Cells(x, 8) = ws3.Cells(90, 8).Value
ws1.Cells(x, 10) = ws4.Cells(18, 6).Value
ws1.Cells(x, 11) = ws4.Cells(18, 7).Value
ws1.Cells(x, 12) = ws4.Cells(18, 8).Value
Else:
End If
Next x
The above is what I'm working with now in place of the while loop.

Comparing two columns with ID

I am comparing two columns A and B.
The columns A and B contains the ID from a Database.
The ID is 13 digits long, but most of the cases they are 11 digits long.
Case 1: If column A has an ID ABC02369000 and column B has an ID ABC02369000 the result is match.
Case 2: If column A has an ID ABC14285500 and column B has an ID ABC1428550000 the result is still match.
Case 3: If column A has an ID ABC15184200 and column B has an ID ABC15144200 the result is no match.
I would like to have a code for this criteria. If it is matched, then highlighted as green, else as red.
I have tried conditional formatting already. I would be glad, if I can have it in code.
Sub RangeTest()
Dim targetWorksheet As Worksheet
Dim i As Long
Dim totalrows As Integer
For i = 2 To 112
Set targetWorksheet = Worksheets("Preparation sheet")
With targetWorksheet
Cells(i, 3) = IIf(Cells(i, 1) = Cells(i, 2), "Yes", "NO")
Cells(i, 3).Interior.Color = IIf(Cells(i, 3) = "Yes", RGB(0, 255, 0), RGB(255, 0, 0))
End With
Next
End Sub
Try the code below:
Option Explicit
Sub RangeTest()
Dim targetWorksheet As Worksheet
Dim i As Long
Dim totalrows As Integer
For i = 2 To 112
Set targetWorksheet = Worksheets("Preparation sheet")
With targetWorksheet
If Left(.Cells(i, 1), 11) = Left(.Cells(i, 2), 11) Then
.Cells(i, 3) = "Yes"
.Cells(i, 3).Interior.Color = RGB(0, 255, 0)
Else
.Cells(i, 3) = "NO"
.Cells(i, 3).Interior.Color = RGB(255, 0, 0)
End If
End With
Next i
End Sub

VBA code to match cell value to column heading and return cell value in a loop

I've been trying to piece this together but have been unsuccessful so far.
Workbook2, with sheet name "Sheet1" has the data which needs to be pulled into Workbook1, with sheet name "DATA".
Workbook 2:
Student ID Date completed Question# Score
101 12/10/2018 1 0
101 12/10/2018 2 5
101 12/10/2018 3 10
101 12/10/2018 4 0
102 12/05/2018 1 10
102 12/05/2018 2 0
Workbook 1:
Student ID Date Completed Question1 2 3 4
101 12/10/2018 0 5 10 0
102 12/05/2018 10 0
What I'm trying to do is get the code to loop through the column with the Question # (in "Sheet1" Workbook 2), and if the student numbers match, and if the question number in Workbook 2 matches the column heading in Sheet "DATA" (Workbook 1) then return the student number, date completed and most importantly, the score value under the matching column heading.
The code I've been trying to use is below. Any suggestions would be welcome:
Public Sub grabqdata()
Dim wbmacro As Workbook
Dim wblean As Workbook
Set wbmacro = Workbooks.Item("MacroFile.xlsm")
Set wblean = Workbooks.Item("Workbook2.xlsx")
Dim wsmacro As Worksheet
Dim wslean As Worksheet
Set wsmacro = wbmacro.Worksheets.Item("Data")
Set wslean = wblean.Worksheets.Item("Sheet1")
Dim leanrange As Range
Set leanrange = wslean.Range("A2:A150000")
Dim headerrange As Range
Set headerrange = wsmacro.Range("A1:G1")
Dim qrange As Range
Set qrange = wslean.Range("D2:D150000")
Dim macrorange As Range
Set macrorange = wsmacro.Range("A:A")
Dim lastrow As Long
lastrow = Cells(Rows.Count, "A").End(xlUp).Row
Dim colm As Long
colm = WorksheetFunction.Match(wsmacro, Range("A1:G1"), 0)
Dim cell As Range
i = 1
For Each cell In leanrange
If leanrange.Range("A2") = macrorange.Range("a2") Then
wsmacro.Range("C2").Offset(i, 0) = wslean.Range("D2").Offset(i, 0)
i = i + 1
End If
Next cell
End Sub
Column C is where the first Q# is (so Q1 or "1").
Thank you!
Not the prettiest, but this should get the job done... This also makes some assumptions, like there aren't multiple completed dates for the same student ID (needed clarification) - also assumes that every student goes through the same question #s (1, 2, 3, etc.).
Option Explicit
Sub Test()
Dim sht As Worksheet, sht2 As Worksheet
Dim i As Long, k As Long
Dim lastrow As Long, lastcol, foundrow As Long, foundcol As Long
Set sht = Workbooks("Testfile1.xlsm").Worksheets("Sheet1")
Set sht2 = Workbooks("Testfile2.xlsm").Worksheets("Sheet1")
lastrow = sht.Cells(sht.Rows.Count, 1).End(xlUp).Row
sht2.Cells.ClearContents
sht2.Cells(1, 1).Value = "Student ID"
sht2.Cells(1, 2).Value = "Date completed"
sht2.Cells(1, 3).Value = "Question # 1"
k = 2
For i = 2 To lastrow
If Application.CountIf(sht2.Range("A:A"), sht.Cells(i, 1).Value) = 0 Then
sht2.Cells(k, 1).Value = sht.Cells(i, 1).Value
sht2.Cells(k, 2).Value = sht.Cells(i, 2).Value
lastcol = sht2.Cells(1, sht2.Columns.Count).End(xlToLeft).Column
sht2.Cells(k, 3).Value = sht.Cells(i, 4).Value
k = k + 1
Else
foundrow = sht2.Range("A:A").Find(What:=sht.Cells(i, 1).Value).Row
On Error Resume Next
foundcol = sht2.Range("1:1").Find(What:="Question # " & sht.Cells(i, 3).Value).Column
On Error GoTo 0
If foundcol = 0 Then
lastcol = sht2.Cells(1, sht2.Columns.Count).End(xlToLeft).Column
sht2.Cells(1, lastcol + 1).Value = "Question # " & sht.Cells(i, 3).Value
sht2.Cells(foundrow, lastcol + 1).Value = sht.Cells(i, 4).Value
Else
sht2.Cells(foundrow, foundcol).Value = sht.Cells(i, 4).Value
End If
End If
Next i
End Sub

Resources