Join cells based on value of a cell vba - vba

I am trying to join cells in a row if a value exists in a cell in that row.
The data has been imported from a .txt file and various sub headers are split along 2, 3 or 4 columns.
The cells cant be merged as the data will only be kept from the first cell.
The only words which are always constant are "contain" and "for" in column B.
What I've tried resembles this:
If cell.Value like "contain", or "for" then join all cells from column "A" to column "H" into column "B", align them centrally and make them bold.
thanks, in advance, for any help.
Edit Here is the code:
Sub Joining()
Dim N As Long, i As Long, r1 As Range, r2 As Range
Dim z As Long
Dim arr() As Variant
z = 1
With Activesheet
N = .Cells(Rows.Count, "A").End(xlUp).Row
For i = 1 To N
If .Cells(i, "B").Value Like "Summary*" Then
arr = .Range(.Cells(i, "A"), .Cells(i, "H")).Value
.Cells(z, "B").Value = Join(arr, " ")
z = z + 1
End If
Next i
End With
End Sub

Not sure if this is exactly what you want but it will get you close:
Sub summary()
Dim sh1 As Worksheet, sh2 As Worksheet
Dim N As Long, i As Long, r1 As Range, r2 As Range
Dim z As Long
Dim arr() As Variant
z = 1
Set sh1 = ActiveSheet
With ActiveWorkbook
Set sh2 = .Worksheets.Add(After:=.Sheets(.Sheets.Count))
End With
With sh1
N = .Cells(Rows.Count, "A").End(xlUp).Row
For i = 1 To N
If .Cells(i, "A").Value Like "Summary*" Then
arr = .Range(.Cells(i, "A"), .Cells(i, "H")).Value
sh2.Cells(z, "A").Value = Join(arr, " ")
z = z + 1
End If
Next i
End With
End Sub

Ok, so I've created an answer, but it ain't pretty (kinda like the whole project I've created).
It works although I'm sure there is a much simpler way of creating it.
Maybe someone can have a go at cleaning it up?
Sub SelRows()
Dim ocell As Range
Dim rng As Range
Dim r2 As Range
For Each ocell In Range("B1:B1000")
If ocell.Value Like "*contain*" Then
Set r2 = Intersect(ocell.EntireRow, Columns("A:G"))
If rng Is Nothing Then
Set rng = Intersect(ocell.EntireRow, Columns("A:G"))
Else
Set rng = Union(rng, r2)
End If
End If
Next
Call JoinAndMerge
If Not rng Is Nothing Then rng.Select
Set rng = Nothing
Set ocell = Nothing
End Sub
Private Sub JoinAndMerge()
Dim outputText As String, Rw As Range, cell As Range
delim = " "
Application.ScreenUpdating = False
For Each Rw In Selection.Rows
For Each cell In Rw.Cells
outputText = outputText & cell.Value & delim
Next cell
With Rw
.Clear
.Cells(1).Value = outputText
.Merge
.HorizontalAlignment = xlCenter
.VerticalAlignment = xlCenter
.WrapText = True
End With
outputText = ""
Next Rw
Application.ScreenUpdating = True
End Sub

Related

VBA Combine columns stack in the loop

I have the issue with stacking in the loop
The macro should combine all columns (changeable number of rows) into one column.
Sub CombineColumns()
Dim xRng As Range
Dim i As Integer
Dim xLastRow As Integer
On Error Resume Next
Set xRng = Application.Range("A1", Range("A1").End(xlDown).End(xlToRight))
xLastRow = xRng.Columns(1).Rows.Count + 1
For i = 2 To xRng.Columns.Count
Range(xRng.Cells(1, i), xRng.Cells(xRng.Columns(i).Rows.Count, i)).Cut
ActiveSheet.Paste Destination:=xRng.Cells(xLastRow, 1)
xLastRow = xLastRow + xRng.Columns(i).Rows.Count
Next
End Sub
Using Array is simple and fast.
Sub test()
Dim Ws As Worksheet, toWS As Worksheet
Dim vDB, vR()
Dim i As Long, j As Integer, n As Long
Set Ws = ActiveSheet
vDB = Ws.UsedRange
r = UBound(vDB, 1)
c = UBound(vDB, 2)
For i = 1 To r
For j = 1 To c
n = n + 1
ReDim Preserve vR(1 To n)
vR(n) = vDB(i, j)
Next j
Next i
Set toWS = Sheets.Add ' set toWs = Sheets(2) ~~> set your sheet
With toWS
.Cells.Clear
.Range("a1").Resize(n) = WorksheetFunction.Transpose(vR)
End With
End Sub
If I got you right you want to do sth. like that
Option Explicit
Sub CombineColumns()
Dim xRng As Range
Dim i As Long
Dim xLastRow As Long
'On Error Resume Next
Set xRng = Application.Range("A1", Range("A1").End(xlToRight))
xLastRow = lastRow(1) + 1
For i = 2 To xRng.Columns.Count
Range(xRng.Cells(1, i), xRng.Cells(lastRow(i), i)).Cut
ActiveSheet.Paste Destination:=xRng.Cells(xLastRow, 1)
xLastRow = lastRow(1) + 1
Next
End Sub
Function lastRow(col As Long, Optional wks As Worksheet) As Long
If wks Is Nothing Then
Set wks = ActiveSheet
End If
lastRow = wks.Cells(wks.Rows.Count, col).End(xlUp).Row
End Function
The code still needs some improvement as it might loop over all columns espeically if there is no data.
This assumes on all your columns you have data on the 2nd row, to correctly identify the last column.
Option Explicit
Public Sub CombineColumns()
Dim LastColumn As Long, LastRow As Long, LastRowA As Long, i As Long, RngAddress As String
With ActiveSheet
' This assumes you have data on row 2 on all columns
LastColumn = .Cells(2, .Columns.Count).End(xlToLeft).Column
For i = 2 To LastColumn
' Get the last row of Col A on each iteration
LastRowA = .Cells(.Rows.Count, 1).End(xlUp).Row + 1
' Get last row of the Col we're checking
LastRow = .Cells(.Rows.Count, i).End(xlUp).Row
' Get the used range address of the current Col
RngAddress = .Range(.Cells(1, i), Cells(LastRow, i)).Address
' Check if we have blank cells among the rows of the current Col
.Range(.Cells(1, i), Cells(LastRow, i)).Value2 = Evaluate("IF(NOT(ISBLANK(" & RngAddress & "))," & RngAddress & ")")
' Compress data (if there's no empty cells in the current Col the below line will give error, that's the role of err handling)
On Error Resume Next
.Range(.Cells(1, i), Cells(LastRow, i)).SpecialCells(xlCellTypeConstants, 4).Delete xlShiftUp
On Error GoTo 0
' Update the last row in case we compressed data
LastRow = .Cells(.Rows.Count, i).End(xlUp).Row
' Paste data in Col A
.Range(.Cells(1, i), Cells(LastRow, i)).Cut Destination:=.Range("A" & LastRowA)
Next i
Application.CutCopyMode = False
End With
End Sub
Maybe this could be a convenient solution for you :
Sub CombineColumns()
Dim LastRow As Long
LastRow = ActiveSheet.UsedRange.Rows(ActiveSheet.UsedRange.Rows.Count).Row
Range("A2:A" & LastRow).Formula = "=B2 & C2 & D2 & E2 & F2 & G2 & H2" 'Insert here the columns you need to be combined
End Sub
Let me know if changes are necessary.

Reverse Loop ignores some cells

I have written a small code that allow me to:
in a defined range (xrng) in column F, find all the cells that contain certain text and once found, select all the cells in the range A:G on the same row and delete them. I have a reverse loop, which work partially, as ignores some cells in the range, specifically the 2nd and the 3rd. Below a before and after pic:
Here my code:
Sub removeapp()
Dim g As Long, xrng As Range, lastrow As Long, i As Long
i = 4
lastrow = Cells(Rows.Count, "F").End(xlUp).Row
Set xrng = Range(Cells(lastrow, "F"), Cells(i, "F"))
For g = xrng.Count To i Step -1
If xrng.Cells(g).Value = "Adjustment" Or xrng.Cells(g).Value = "Approved" Then
Range(Cells(xrng.Cells(g).Row(), "A"), Cells(xrng.Cells(g).Row(), "G")).Delete
End If
Next
End Sub
Could you help me to figure out why?
Also, the code runs really slow... if you have any tip to make it slighlty faster would be great!
Try this, please:
Sub removeappOrig()
Dim xrng As Range, lastrow As Long, sh As Worksheet
Set sh = ActiveSheet 'good to put here your real sheet
lastrow = sh.Cells(sh.Rows.count, "F").End(xlUp).Row
Set xrng = sh.Range("A4:F" & lastrow)
xrng.AutoFilter field:=6, Criteria1:="=Adjustment", Operator:=xlOr, _
Criteria2:="=Approved", VisibleDropDown:=False
Application.DisplayAlerts = False
xrng.SpecialCells(xlCellTypeVisible).Delete
Application.DisplayAlerts = True
sh.AutoFilterMode = False
End Sub
The next code is also fast enough since it iterates between array elements (in memory), not deletes row by row (it creates a ranges Union) and delete all at once:
Private Sub remoRangesAtOnce()
Dim i As Long, lastRow As Long, sh As Worksheet
Dim arrF As Variant, rng As Range, rngDel As Range
Set sh = ActiveSheet 'please name it according to your sheet name
lastRow = sh.Cells(sh.Rows.count, "F").End(xlUp).Row
Set rng = sh.Range("F4:F" & lastRow)
arrF = rng.Value
For i = LBound(arrF) To UBound(arrF)
If arrF(i, 1) = "Adjustment" Or arrF(i, 1) = "Approved" Then
If rngDel Is Nothing Then
Set rngDel = sh.Range(sh.Range("A" & i + 3), sh.Range("F" & i + 3))
Else
Set rngDel = Union(rngDel, sh.Range(sh.Range("A" & i + 3), sh.Range("F" & i + 3)))
End If
End If
Next i
If Not rngDel Is Nothing Then rngDel.Delete xlShiftUp
End Sub

select adjacent cell in entire column VBA

Code :
Option Explicit
Sub selectAdjacentBelowCells()
Dim r, c As Integer
Dim r1, r2, c1, c2 As Integer
Dim i As Integer
Dim j As Integer
Dim st As String
Dim lastRow As Integer
With ActiveCell
r = .Row
c = .Column
End With
r1 = r
r2 = r
lastRow = ActiveSheet.Cells(Rows.Count, c).End(xlUp).Row
Dim value As Integer
value = Cells(r, c).value
Dim value1 As Integer
Dim value2 As Integer
Dim myUnion As Range
Dim myCell As Range
For i = r1 To lastRow - 1
'selects adjacent cells below
value1 = Cells(i + 1, c).value
If (value1 = value) Then
Range(Cells(i, c), Cells(i + 1, c)).Select
Else
Exit For
End If
Next
Dim x As Integer
x = Cells(r2 - 1, c).value
For x = r2 To (r2 + 1) - r2 Step -1
'selects adjacent cells above
value2 = Cells(x - 1, c).value
If (value2 = value) Then
Range(Cells(r, c), Cells(x - 1, c)).Select
Else
Exit For
End If
Next
End Sub
Column in excel :
10
20
30
40
50
60
60(this cell is selected and then vba code is executed)
60
70
80
90
I need to select adjacent cells in entire column. It selects adjacent cells, but first it selects adjacent cells below and then above. But the selection changes to above cells and below cells are deselected after the first piece of code runs.
I know it can be done through Union, I tried using it but I got errors everytime. Got argument is not optional error and then I had to remove the Union code and the above code is what I now have.
Please give this a try to see if that works for you.
Sub selectAdjacentBelowCells()
Dim targetCell As Range, Rng As Range, cell As Range, LastCell As Range, uRng As Range
Dim lr As Long
Dim firstAddress As String
lr = Cells(Rows.Count, 1).End(xlUp).Row
Set targetCell = ActiveCell
Set LastCell = Range("A:A").SpecialCells(xlCellTypeLastCell)
With Range("A1:A" & lr)
Set cell = .Find(what:=targetCell.value, after:=LastCell, LookIn:=xlValues, lookat:=xlWhole)
If Not cell Is Nothing Then
firstAddress = cell.Address
Do
If uRng Is Nothing Then
Set uRng = cell
Else
Set uRng = Union(uRng, cell)
End If
Set cell = .FindNext(cell)
Loop While Not cell Is Nothing And cell.Address <> firstAddress
End If
End With
For Each Rng In uRng.Areas
If Not Intersect(Rng, targetCell) Is Nothing Then
Rng.Select
Exit For
End If
Next Rng
End Sub

Cut and Paste into a sheet with Case-Select

I am new to writing macros and trying to write one for work. Below is a piece of code I have been fighting with. I want it to look at sheet "NG304" and find key words listed in column B. If the key words are there, move them to the second spreadsheet "Payroll Detail". Issues i'm having - the code is not going through the whole list and it doesn't seem to be pasting in the next available row on the payroll detail spreadsheet (it will simply paste on top of my header).
Code:
Dim Findme As String, Findwhat As String, c As Range
With ActiveWorkbook.Worksheets("NG304")
For Each c In .Range(.Cells(2, "B"), .Cells(Rows.Count, "B").End(xlUp))
Findwhat = vbNullString
Findme = StrConv(c.Value2, vbProperCase)
Select Case True
Case Findme Like "VCIP"
Findwhat = "VCIP"
Case Findme Like "Company Labor"
Findwhat = UCase(Findme)
Case Else
'do nothing
End Select
If CBool(Len(Findwhat)) Then
With .Parent.Worksheets("NG304")
c.EntireRow.Cut Destination:=Worksheets("Payroll Detail").Range("A" & lastrow + 1)
lastrow = lastrow + 1
End With
End If
Next c
End With
This will filter each value defined in K_WORDS (at the top), and move the rows to the other sheet:
Option Explicit
Public Sub moveKeywordRows()
Const K_WORDS As String = "VCIP,Company Labor" '<------- Defined keywords
Dim wsFrom As Worksheet, wsDest As Worksheet, kw As Variant, i As Long, lr As Long
Set wsFrom = ThisWorkbook.Worksheets("NG304")
Set wsDest = ThisWorkbook.Worksheets("Payroll Detail")
kw = Split(K_WORDS, ",")
Application.ScreenUpdating = False
For i = 0 To UBound(kw)
lr = wsDest.Cells(wsDest.Rows.Count, "B").End(xlUp).Row
With wsFrom.UsedRange
.AutoFilter Field:=2, Criteria1:="=" & kw(i)
.Copy
wsDest.Cells(lr, "A").PasteSpecial xlPasteAll
.SpecialCells(xlCellTypeVisible).EntireRow.Delete
End With
Application.CutCopyMode = False
wsDest.Activate: wsDest.Cells(1, "A").Select
Next
wsDest.UsedRange.EntireColumn.AutoFit
With wsFrom
.Activate 'wsFrom.UsedRange.AutoFilter '.ShowAllData
End With
Application.ScreenUpdating = True
End Sub
This is your posted code, with some adjustments - it seems to be working:
Public Sub moveKeywordRows1()
Dim FindMe As String, FindWhat As String, c As Range, lr As Long, wsDest As Worksheet
Set wsDest = ThisWorkbook.Worksheets("Payroll Detail")
With ThisWorkbook.Worksheets("NG304")
Application.ScreenUpdating = False
For Each c In .Range(.Cells(2, "B"), .Cells(.Rows.Count, "B").End(xlUp))
FindMe = StrConv(c.Value2, vbProperCase)
FindWhat = vbNullString
Select Case UCase(FindMe)
Case "VCIP": FindWhat = "VCIP"
Case UCase("Company Labor"): FindWhat = "Company Labor"
End Select
If Len(FindWhat) > 0 Then
c.EntireRow.Cut Destination:=wsDest.Range("A" & lr + 1)
lr = lr + 1
End If
Next
Application.ScreenUpdating = True
End With
End Sub

Remove row if cell value not in list

I have 2 sheets : in the first i have date and in sheet2 i have a list of names in column A . I want to delete all the rows that don't have the names from sheet2 in the column O from the first sheet. The code just deletes everything from the first sheet. Any help is welcomed.
Sub Demo()
Dim Rng As Range, List As Object, Rw As Long
Dim x As Date
x = Now()
Set List = CreateObject("Scripting.Dictionary")
With Sheets("Sheet2")
For Each Rng In .Range("A1", .Range("A" & Rows.Count).End(xlUp))
If Not List.Exists(Rng.Value) Then
List.Add Rng.Value, Nothing
End If
Next
End With
With Sheets("query " & Format(x, "dd.mm.yyyy"))
For Rw = .Range("O" & Rows.Count).End(xlUp).Row To 1 Step -1
If Not List.Exists(.Cells(Rw, "O").Value) Then
.Rows(Rw).Delete
End If
Next
End With
Set List = Nothing
End Sub
I'm not sure if this does exactly what you wants, but it does something very similar. To be clear:
Marks the cell adjacent to the list of names in Sheet1, if the name is found, then subsequently deletes the entire row if the the cell in said adjacent column is empty.
Sub Macro()
Dim r As Long
Dim r2 As Long
Dim counter As Long
Dim counter2 As Long
Range("O1").Select
Selection.End(xlDown).Select
r = ActiveCell.Row
Sheets(ActiveSheet.Index + 1).Select
Range("A1").Select
Selection.End(xlDown).Select
r2 = ActiveCell.Row
Range("A1").Select
For counter = 1 To r2
needle = ActiveCell.Value
Sheets(ActiveSheet.Index - 1).Select
On Error GoTo NotFound
Range(Cells(1, 15), Cells(r, 15)).Find(needle).Select
Selection.Offset(0, 1).Value = "found"
NotFound:
Sheets(ActiveSheet.Index + 1).Select
Selection.Offset(1, 0).Select
Next
Sheets(ActiveSheet.Index - 1).Select
Range("P1").Select
For counter2 = 1 To r
If ActiveCell.Value = "" Then Selection.EntireRow.Delete
Selection.Offset(1, 0).Select
Next
Cleanup:
Range("P1:P10000").Value = ""
End Sub
It is however, rather ugly and inefficient code. Lmk if there's something that needs changing!
i would do it like this:
Dim i as integer
dim x as integer
Dim rngSearch as Range
Dim strName as String
Dim ws1 as Worksheet
dim ws2 as Worksheet
Set ws1 = Thisworkbook.worksheets(1)
Set ws2 = Thisworkbook.worksheets(2)
x = ws1.cells(ws1.rows.count,1).end(xlup).row
for i = 2 to x
strName = ws1.cells(i, 1)
set rngSearch = ws2.columns(15).find(strName)
if rngSeach is nothing then
ws1.rows(i).entirerow.delete
i = i-1
end if
next i
It's not tested but it should work like this.
Edit: I think you have to put the worksheets in right order. I think i mixed them up here.