VBA checking if a row in a sheet contains multiple variables - vba

I have a problem looping through a sheet to find a row matching some variables.
I've got 8 columns per row, and I want to find a row that contains 6 variables, one empty cell and one cell with value 0. Like this:
- | A | B | C | D | E | F | G | H |
i | x1 | | x2 | 0 | x3 | x4 | x5 | x6 |
Where i is a row number and x1, x2,.. x6 are variables obtained from a CSV file. I want to check if my 'list' of variables {x1, ,x2,0,x3,x4,x5,x6} is an existing row in a sheet. So I want the program to do something If (Ai = x1 And Bi = "" And Ci = x2 And Di = "0" And Ei = x3 And Fi = x4 And Gi = x5 And Hi = x6) and do nothing when Else.
So I need to loop through all the rows and check if all variables are in 1 row.
At the moment I tried this but it doesn't seem to work.
LastCol = 8
LastRow = ThisWorkbook.Sheets("Boekingen AMS-IAD").Range("A" & Rows.Count).End(xlUp).Row
For i = 1 To LastRow
For j = 1 To LastCol
'Tried with only 1 criteria, still didn't work
If (ThisWorkbook.Sheets("Boekingen AMS-IAD").Cells(i, j).Value = x1) Then
Accept = "nvt"
End If
Next j
Next i

You can try something like this. I left everything pretty much as you had it with a couple of exceptions.
lastcol = 8
Dim vars
ReDim vars(1 To lastcol)
'Set vars() to the values you're looking for in the columns.
LastRow = ThisWorkbook.Sheets("Boekingen AMS-IAD").Range("A" & Rows.Count).End(xlUp).Row
For i = 1 To LastRow
accept = ""
met = 0
For j = 1 To lastcol
With ThisWorkbook.Sheets("Boekingen AMS-IAD").Cells(i, j)
If .Value = vars(j) Then
met = met + 1
End If
End With
Next j
If met = lastcol Then accept = "nvt"
'At this point you have to do something with the row you just
' found--maybe leave the loop and do something, or do something
' before going to the next row.
Next i

I made this quick little test sub in a new excel folder, renamed Sheet1 to your sheet's name and it works excellently:
Sub testing()
Dim ws As Worksheet
Dim rng As Range
Set ws = ThisWorkbook.Sheets("Boekingen AMS-IAD")
LastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
For i = 1 To LastRow
If ws.Cells(i, 1).Value = x1 And _
ws.Cells(i, 2).Value = "" And _
ws.Cells(i, 3).Value = x2 And _
ws.Cells(i, 4).Value = "0" And _
ws.Cells(i, 5).Value = x3 And _
ws.Cells(i, 6).Value = x4 And _
ws.Cells(i, 7).Value = x5 And _
ws.Cells(i, 8).Value = x6 Then
'MsgBox "nvt at row " & i
Accept = "nvt"
End If
Next i
End Sub
This should spit out "nvt" when the line follows your variables :)
PS - anyone looking to test this code, you just need to add the following under Dim rng as Range:
Dim x1 As Integer
Dim x2 As Integer
Dim x3 As Integer
Dim x4 As Integer
Dim x5 As Integer
Dim x6 As Integer
x1 = 1
x2 = 1
x3 = 1
x4 = 1
x5 = 1
x6 = 1

I fixed the issue, the problem wasn't in looping through the sheet, but in a value of a variable. The date was changed from D-M-Y to M-D-Y when I read it from the Excel sheet. But I fixed that, for the ones that are interested in the answer: VBA changes date format from D-M-Y to M-D-Y

Related

Print array values a variable number of times

I am trying to write a macro that will print out the values in an array depending on conditions in other cells. I have gotten the macro to print out one value in the array, but not the others. The spreadsheet looks like this:
Column 1 | Column 2
___________________
L1 |
L1 |
L2 |
L3 |
L1 |
L5 |
L1 |
The array looks like this: List = Array("Person1", "Person2", "Person3") and what I am trying to do is print Person1, Person2 etc. for every value that says L1 up to that last L1 value. It should look like the example below.
Column 1 | Column 2
___________________
L1 | Person1
L1 | Person2
L2 |
L3 |
L1 | Person3
L5 |
L1 | Person1
The macro below partially works, but it only prints one person, Person3. Any help would be appreciated!
Sub Practice()
Dim i, j, k As Integer
Dim List As Variant
Dim LastRow As Long, CountL As Long
Dim ws As Worksheet
Set ws = ActiveWorkbook.Sheets("Sheet1")
List = Array("Person1", "Person2", "Person3")
LastRow = ws.Cells(Rows.Count, "C").End(xlUp).Row - 1
For i = LBound(List) To UBound(List)
For j = 2 To LastRow
If ws.Cells(j, 3).Value = "L1" Then
ws.Cells(j, 4) = List(i)
Else 'Do Nothing
End If
Next j
Next i
End Sub
Note that the "L" values are in Column C and the person names in Column D in the actual spreadsheet, which is why the columns in the macro don't match the columns in the sample data I added here.
Take a look at the below example:
Sub Practice()
Dim ws As Worksheet
Dim List As Variant
Dim LastRow As Long
Dim i As Integer
Dim j As Integer
Set ws = ThisWorkbook.Sheets("Sheet1")
List = Array("Person1", "Person2", "Person3")
LastRow = ws.Cells(ws.Rows.Count, "C").End(xlUp).Row
i = 0
For j = 2 To LastRow
If ws.Cells(j, 3).Value = "L1" Then
ws.Cells(j, 4) = List(i Mod 3)
i = i + 1
End If
Next
End Sub
Your code is currently repeating its actions for each value in the list, and each iteration is assigning a value to every L1 row, and overwriting what was written there in the previous iteration.
You actually need to keep a counter of which value from your array you want to write next:
Sub Practice()
'You should declare the type of each variable, or else they will be Variant
'Dim i, j, k As Integer
Dim i As Integer, j As Integer, k As Integer
Dim List As Variant
Dim LastRow As Long, CountL As Long
Dim ws As Worksheet
Set ws = ActiveWorkbook.Sheets("Sheet1")
List = Array("Person1", "Person2", "Person3")
'You should fully qualify objects such as Range, Cells and Rows
'LastRow = ws.Cells(Rows.Count, "C").End(xlUp).Row - 1
LastRow = ws.Cells(ws.Rows.Count, "C").End(xlUp).Row '<-- not sure why you subtracted 1
i = LBound(List)
For j = 2 To LastRow
If ws.Cells(j, 3).Value = "L1" Then
ws.Cells(j, 4) = List(i)
i = i + 1
If i > UBound(List) Then
i = LBound(List)
End If
End If
Next j
End Sub

Excel Macro Transpose only few columns

I have a excel sheet looks like this: "Sheet1" & "Sheet2" and I wanted the result as shown in "Sheet3".
Sample Data
Eventually I would like to put a "Button" in a separate sheet (Control Panel) and when clicking on it I need to combine the data from "Sheet1" and "Sheet2" with the transpose effect as shown in "Sheet3".
How can I automate this using macro since there are ~2000 "rows" in Sheet 1 and ~1000 in Sheet 2. I'm new to macro so hopefully I can make this automated otherwise I'm copying and pasting all of them manually.
Thanks!
It might be helpful to use a function that returns the last row of a worksheet:
Public Function funcLastRow(shtTarget As Worksheet, Optional iColLimit As Integer = -1) As Long
If iColLimit = -1 Then
iColLimit = 256
End If
Dim rowMaxIndex As Long
rowMaxIndex = 0
Dim ctrCols As Integer
For ctrCols = 1 To iColLimit
If shtTarget.Cells(1048576, ctrCols).End(xlUp).Row > rowMaxIndex Then
rowMaxIndex = shtTarget.Cells(1048576, ctrCols).End(xlUp).Row
End If
Next ctrCols
funcLastRow = rowMaxIndex
End Function
You could use it simply like so:
Dim lLastRow As Long
lLastRow = funcLastRow(Sheets(1))
Please let us know if that worked for you thanks
Here is an all formula solution (No Macro)
Data is in Sheet1 A to I and Sheet2 A to G
I am assuming you have only 6 departments. although if you have additional, the formulas need very little or may be no modification.
In Sheet 3
Get the userID repeated six times
A2 = INDEX(Sheet1!A:A,1+QUOTIENT(ROW()-ROW($A$2)+6,6))
Get Name, Gender & Country
B2 = VLOOKUP($A2,Sheet1!$A$2:$I$3000,COLUMNS($A$1:B$1),FALSE)
C2 = VLOOKUP($A2,Sheet1!$A$2:$I$3000,COLUMNS($A$1:C$1),FALSE)
D2 = VLOOKUP($A2,Sheet1!$A$2:$I$3000,COLUMNS($A$1:D$1),FALSE)
Get Access to department. The "" & ... is to avoid 0 in case the resulting cell was blank.
E2 = "" & IF(SUMPRODUCT(--(Sheet1!$A$1:$I$1=F2))>0,HLOOKUP(F2,Sheet1!$A$1:$I$3000,MATCH(A2,Sheet1!$A$1:$A$3000,0),FALSE),HLOOKUP(F2,Sheet2!$A$1:$G$3000,MATCH(A2,Sheet2!$A$1:$A$3000,0),FALSE))
F2:F7 the departments are Input manually (no formula). F8 is linked to F2 so that the depts repeat when dragged down
G2 = "" & IF(SUMPRODUCT(--(Sheet1!$A$1:$I$1=F2))>0,INDEX(Sheet1!$I$1:$I$3000,MATCH(A2,Sheet1!$A$1:$A$3000,0)),INDEX(Sheet2!$G$1:$G$3000,MATCH(A2,Sheet1!$A$1:$A$3000,0)))
If you need, I can prepare a google sheet to demo. Cheers.
This code works very well for Transpose and concatenate of big data.
Sub ConcatData()
Dim X As Double
Dim DataArray(5000, 2) As Variant
Dim NbrFound As Double
Dim Y As Double
Dim Found As Integer
Dim NewWks As Worksheet
Cells(1, 1).Select
Let X = ActiveCell.Row
Do While True
If Len(Cells(X, 1).Value) = Empty Then
Exit Do
End If
If NbrFound = 0 Then
NbrFound = 1
DataArray(1, 1) = Cells(X, 1)
DataArray(1, 2) = Cells(X, 2)
Else
For Y = 1 To NbrFound
Found = 0
If DataArray(Y, 1) = Cells(X, 1).Value Then
DataArray(Y, 2) = DataArray(Y, 2) & ", " & Cells(X, 2)
Found = 1
Exit For
End If
Next
If Found = 0 Then
NbrFound = NbrFound + 1
DataArray(NbrFound, 1) = Cells(X, 1).Value
DataArray(NbrFound, 2) = Cells(X, 2).Value
End If
End If
X = X + 1
Loop
Set NewWks = Worksheets.Add
NewWks.Name = "SummarizedData"
Cells(1, 1).Value = "Names"
Cells(1, 2).Value = "Results"
X = 2
For Y = 1 To NbrFound
Cells(X, 1).Value = DataArray(Y, 1)
Cells(X, 2).Value = DataArray(Y, 2)
X = X + 1
Next
Beep
MsgBox ("Summary is done!")
End Sub

Creating a unique entry for each line item in Excel

I need help in creating a macro in Excel wherein it grabs a certain cell and copies the entire row x number of times depending on the cell's contents.
To make it clear, let's say I have 2 rows:
| Order # | Item | Qty |
| 30001 | bag | 3 |
| 30002 | pen | 1 |
What I want the macro to do is grab the number under the Qty column and copy the entire row and insert a new line with the exact same contents under it. The number of times it does this depends on the number in the Qty cell. Also, it appends a three digit number in the Order # cell to make it a unique reference point. What the end-result should be:
| Order # | Item | Qty |
| 30001-001 | bag | 1 |
| 30001-002 | bag | 1 |
| 30001-003 | bag | 1 |
| 30002-001 | pen | 1 |
It's hard to explain it here but I hope you get the point. Thanks in advance, gurus!
The following code supports blank lines in the middle of the data.
If Qty = 0, it won't write the Item in the output table.
Please insert at least 1 row of data, because it won't work if there is no data :)
Option Explicit
Sub caller()
' Header at Row 1:
' "A1" = Order
' "B1" = Item
' "C1" = Qty
'
' Input Data starts at Row 2, in "Sheet1"
'
' Output Data starts at Row 2, in "Sheet2"
'
' Sheets must be manually created prior to running this program
Call makeTheThing(2, "Sheet1", "Sheet2")
End Sub
Sub makeTheThing(lStartRow As Long, sSheetSource As String, sSheetDestination As String)
Dim c As Range
Dim rOrder As Range
Dim sOrder() As String
Dim sItem() As String
Dim vQty As Variant
Dim sResult() As String
Dim i As Long
' Reads
With ThisWorkbook.Sheets(sSheetSource)
Set rOrder = .Range(.Cells(lStartRow, 1), .Cells(.Cells(.Rows.Count, 1).End(xlUp).Row, 1)) ' It will work if there are blank lines in the middle!
i = rOrder.Rows.Count
ReDim sOrder(1 To i)
ReDim sItem(1 To i)
ReDim vQty(1 To i)
i = 1
For Each c In rOrder
sOrder(i) = Trim(c.Text)
sItem(i) = Trim(c.Offset(0, 1).Text)
vQty(i) = c.Offset(0, 2).Value
i = i + 1
Next c
End With
' Processes
sResult = processData(sOrder, sItem, vQty)
' Writes
ThisWorkbook.Sheets(sSheetDestination).Range("A" & lStartRow).Resize(UBound(sResult, 1), UBound(sResult, 2)).Value = sResult
End Sub
Function processData(sOrder() As String, sItem() As String, vQty As Variant) As String()
Dim i As Long
Dim j As Long
Dim k As Long
Dim sResult() As String
j = WorksheetFunction.Sum(vQty) ' That's why vQty had to be Variant!
ReDim sResult(0 To j, 1 To 3)
k = 0
For i = 1 To UBound(sOrder)
For j = 1 To vQty(i)
sResult(k, 1) = sOrder(i) & "-" & Format(j, "000")
sResult(k, 2) = sItem(i)
sResult(k, 3) = "1"
k = k + 1
Next j
Next i
processData = sResult
End Function
I hope it helps you. I had fun making it!
One way: Walk down the qty column inserting as needed then jumping to the next original row;
Sub unwind()
Dim rowCount As Long, cell As Range, order As String, i As Long, r As Long
Set cell = Range("C1")
rowCount = Range("C" & rows.Count).End(xlUp).Row
For i = 1 To rowCount
order = cell.Offset(0, -2).Value
For r = 0 To cell.Value - 1
If (r > 0) Then cell.Offset(r).EntireRow.Insert
cell.Offset(r, 0).Value = 1
cell.Offset(r, -1).Value = cell.Offset(0, -1).Value
cell.Offset(r, -2).Value = order & "-" & Format$(r + 1, "000")
Next
Set cell = cell.Offset(r, 0)
Next
End Sub

Excel Barcode Scanner Column Data to Row

I am using a barcode scanner to do inventory with large quantities and I want to enter the data into excel. I can change the way that the scanner behaves after each scan to do things like tab, return, etc. but my big problem is that in order to efficiently provide the quantity I have to scan the item code (7 digits) and then scan the quantities from 0 to 9 in succession. Such that 548 is really 5, 4, 8 and when using excel it puts each number into a new cell. What I would like to do, but don't have the VBA chops to do it is to have excel check to see if the length is 7 digits or one digit. For each one digit number it should move the number to the next cell in the same row as the previous 7 digit number such that each successive one digit number is combined as if excel were concatenating the cells. Then it should delete the single digits in the original column and have the next row start with the 7 digit barcode number.
I hope this makes sense.
Example:
7777777
3
4
5
7777778
4
5
6
7777779
7
8
9
Should become:
| 7777777 | 345 |
| 7777778 | 456 |
| 7777779 | 789 |
Thanks!!
I set up my worksheet like this:
then ran the below code
Sub Digits()
Application.ScreenUpdating = False
Dim i&, r As Range, j&
With Columns("B:B")
.ClearContents
.NumberFormat = "#"
End With
For i = 1 To Cells(Rows.Count, 1).End(xlUp).Row
Set r = Cells(i, 1)
If Len(r) = 7 Then
j = 1
Do Until ((Len(r.Offset(j, 0).Text) = 7) Or (IsEmpty(r.Offset(j, 0))))
Cells(i, 2) = CStr(Cells(i, 2).Value) & CStr(r.Offset(j, 0))
j = j + 1
Loop
End If
Set r = Nothing
Next
For i = Cells(Rows.Count, 1).End(xlUp).Row To 1 Step -1
If Len(Cells(i, 1)) < 7 Then Rows(i & ":" & i).Delete
Next i
Columns.AutoFit
Application.ScreenUpdating = True
End Sub
and the results Ive got:
This is what I did with what you started but I think your newer solution will work better. Thank you so much mehow!
Sub Digits()
Application.ScreenUpdating = False
Dim i, arr, r As Range
Dim a, b, c, d, e
Dim y
For i = 1 To Cells(Rows.Count, 1).End(xlUp).Row
Set r = Cells(i, 1)
Set a = Cells(i + 1, 1)
Set b = Cells(i + 2, 1)
Set c = Cells(i + 3, 1)
Set d = Cells(i + 4, 1)
Set e = Cells(i + 5, 1)
If Len(a) = 7 Then
y = 0
ElseIf Len(b) = 7 Then
y = 1
ElseIf Len(c) = 7 Then
y = 2
ElseIf Len(d) = 7 Then
y = 3
ElseIf Len(e) = 7 Then
y = 4
Else:
y = 0
End If
If Len(r) = 7 Then
arr = Range("A" & i & ":A" & i + y).Value
Range("B" & i & ":F" & i) = WorksheetFunction.Transpose(arr)
End If
Next
Cells.Replace "#N/A", "", xlWhole
Application.ScreenUpdating = True
End Sub

VBA: Loop isn't working as it should

Being new here I don't know if I can state my question really clear, but I'll try.
I have this VBA code which extracts certain information from an access database into an excel sheet in relation to another excel sheet. And being new to vba coding I don't know how good or correct is the method I'm using.
My problem is with the loop that's supposed to work only when 'fam' is equal to 'z' the value in a column. So, in more detail, column D from the worksheet "gbe..." contains the first 2 values of the numbers from column B, and when I give the input from my keyboard a value that is stored in 'fam' the code is supposed to search in the entire column for that value and then continue to extract from the database only the data that I'm asking for, but the loop doesn't stop when fam <> z.
I hope that you can help me, everything that I've learned about vba is from here, but now I ran out of ideas.
Sub Dateinitiale()
Dim data As Date
'Dim codprodus, codrola As Variant
Dim i, j, k, m, n, s, x, y, z2, z3 As Integer
Dim z As Variant
Dim olddb As Database, OldWs As Workspace
Set OldWs = DBEngine.Workspaces(0)
Set olddb = OldWs.OpenDatabase("C:\BusData\rfyt\xxg\_lgi\data\FyTMaes.Mdb") 'cale BD pentru importul datelor
Cells(1, 1) = "Cod Produs"
Cells(1, 2) = "Nr Rola"
Cells(1, 3) = "Masina "
Cells(1, 4) = "Data inceput"
Cells(1, 5) = "Data sfarsit"
fam = Application.InputBox("Introduceti Familia CAB", "FamCAB Search")
If fam = False Then Exit Sub
z = Worksheets("gbe03407e").Cells(2, 4).Value
x = 2
y = 2
z2 = 2
Do Until z = ""
z = Worksheets("gbe03407e").Cells(z2, 4).Value
z3 = z2
Do While fam = z
codrola = Worksheets("gbe03407e").Cells(z3, 2).Value
Cells(y, 2).Value = codrola
Cells(y, 1).Value = codprodus
' write the values read from the menu into cells
Sql = "select initra, fintra, codmaq, codsuc from tblTRAZA where numser like '" & codrola & "' and (TIPTRA='F' or TIPTRA='FA' or TIPTRA='FD' or TIPTRA='FF' or TIPTRA='FM' or TIPTRA='FT' or TIPTRA='FC' or TIPTRA='FK' or TIPTRA='FN' or TIPTRA='FQ' or TIPTRA='FR')order by fecmov"
Set rs = olddb.OpenRecordset(Sql)
On Error Resume Next
rs.MoveFirst
Do Until rs.EOF
Cells(y, 1).Value = rs("codsuc")
Cells(y, 3).Value = rs("codmaq")
Cells(y, 4).Value = rs("initra")
Cells(y, 5).Value = rs("fintra")
rs.MoveNext
Loop
x = x + 1
y = y + 8
z3 = z3 + 1
Loop
z2 = z2 + 1
Loop
end sub
It seems you're not updating either z or fam inside this loop:
Do While fam = z
Which would lead to an infinite loop. If i understand correctly what you're trying to do, you should replace it with
If fam = z Then
Also, you probably want to test if your query returns any value. Something like this:
If fam = z Then
...
Set rs = olddb.OpenRecordset(Sql)
If Not rs.EoF Then
...
End If
...
End If