Invalid use of Property Error: For each row in Table, apply to only the cells of the first column - vba

How can I modify the following to loop over the first column of a table in word rather than applying it to all cells of a table?
Additionally, how can I have this iterate over every table within the document?
Sub AddToEveryCell()
Dim tbl As Table
Dim rw As Row
Dim cl As Cell
If Selection.Information(wdWithInTable) Then
Set tbl = ActiveDocument.Tables(1)
For Each rw In tbl.Rows
For Each cl In rw.Cells
cl.Range.Text = _
Left(cl.Range.Text, Len(cl.Range.Text) - 2) _
& "|" ' <= the character you want to add
Next cl
Next rw
Else
MsgBox "Put the cursor in the table and rerun this macro."
End If
End Sub
Attempt I have explored is:
Dim tbl As Table
Dim rw As Row
Dim cl As Cell
If Selection.Information(wdWithInTable) Then
Set tbl = ActiveDocument.Tables(1)
For Each rw In tbl.Rows
cl = rw.Cells(1) ' only loop through the first column
cl.Range.Text = _
Left(cl.Range.Text, Len(cl.Range.Text) - 2) _
& "|" ' <= the character you want to add
Next rw
Else
MsgBox "Put the cursor in the table and rerun this macro."
End If
However, I am getting an invalid use of property error.

I tried the second of your attempts and initially got the same error as you. Then I added a "Set" before cl = rw.Cells(1), I had a vague memory of having this problem before... then it worked just fine.
Objects and variables needs to be assigned using set, according to https://learn.microsoft.com/en-us/office/vba/language/reference/user-interface-help/set-statement
I pasted the macro that worked on my computer below.
Sub q2()
'
Dim tbl As Table
Dim rw As Row
Dim cl As Cell
If Selection.Information(wdWithInTable) Then
Set tbl = ActiveDocument.Tables(1)
For Each rw In tbl.Rows
Set cl = rw.Cells(1) ' only loop through the first column
Debug.Print "in for"
cl.Range.Text = _
Left(cl.Range.Text, Len(cl.Range.Text) - 2) _
& "|" ' <= the character you want to add
Next rw
Else
MsgBox "Put the cursor in the table and rerun this macro."
End If
'
'
End Sub

Try the following if statement :
If Selection.Information(wdWithInTable) Then
For Each tbl In ActiveDocument.Tables ' loop through all tables in the document
For Each rw In tbl.Rows
cl = rw.Cells(1) ' only loop through the first column
cl.Range.Text = _
Left(cl.Range.Text, Len(cl.Range.Text) - 2) _
& "|" ' <= the character you want to add
Next rw
Next tbl
Else
MsgBox "Put the cursor in the table and rerun this macro."
End If
Hope this helps

If you only want to process the first column you should loop through the cells of that column, rather than looping through the rows. To apply the code to all the tables in the document is as simple as looping through the tables.
Sub AddToFirstColCells()
Dim tbl As Table
Dim cl As Cell
For Each tbl In ActiveDocument.Tables
For Each cl In tbl.Columns(1).Cells
cl.Range.Text = _
Left(cl.Range.Text, Len(cl.Range.Text) - 2) _
& "|" ' <= the character you want to add
Next cl
Next tbl
End Sub

Related

vb code for selecting the 1st empty cell in column a of a word table

I have been trying to get some code to automatically select the 1st empty cell in column A of a word table I have tried using examples of previous questions but not all of them wok and others just give a message box answer of the row and column. I have macros that input data into the table then sect the next row down in column A. But if my cursor isn't in the right place, ie, Column A and next empty cell then the data is written out of alignment column wise and often row wise.
one macro inserts time in the cell where ever the cursor is.
. I would like to select the the 1st empty cell in column A then enter the time maccro.
Selection.InsertDateTime DateTimeFormat:="HH:mm", InsertAsField:=False, _
DateLanguage:=wdEnglishUK, CalendarType:=wdCalendarWestern, _
InsertAsFullWidth:=False
Thankyou in advance
Regards jrfmps
I could be wrong but there is no direct way to find the 1st empty cell in a specific column of a word table. You will have to loop as shown below.
Code:
Option Explicit
Sub Sample()
Dim tbl As Table
Dim aCell As Cell
Dim aCol As Column
'~~> Set this to the relevant table
Set tbl = ActiveDocument.Tables(1)
'~~> This is set for Col 1 (A)
Set aCol = tbl.Columns(1)
'~~> loop through cell in Col 1
For Each aCell In aCol.Cells
If aCell.Range.Text = Chr(13) & Chr(7) Then
MsgBox "Cells (" & aCell.RowIndex & "," & aCell.ColumnIndex & ") is empty"
Exit For
End If
Next aCell
End Sub
Screenshot
Avoid the use of Selection. Work directly with object(s). Here is how you can adapt your code to the above code...
Option Explicit
Sub Sample()
Dim tbl As Table
Dim aCell As Cell
Dim aCol As Column
Dim rng As Range
'~~> Set this to the relevant table
Set tbl = ActiveDocument.Tables(1)
'~~> This is set for Col 1 (A)
Set aCol = tbl.Columns(1)
'~~> loop through cell in Col 1
For Each aCell In aCol.Cells
If aCell.Range.Text = Chr(13) & Chr(7) Then
MsgBox "Cells (" & aCell.RowIndex & "," & aCell.ColumnIndex & ") is empty"
Set rng = tbl.Cell(aCell.RowIndex, aCell.ColumnIndex).Range
rng.Collapse wdCollapseStart
rng.InsertDateTime DateTimeFormat:="HH:mm", _
InsertAsField:=False, _
DateLanguage:=wdEnglishUK, _
CalendarType:=wdCalendarWestern, _
InsertAsFullWidth:=False
Exit For
End If
Next aCell
End Sub

Loop through table, shading empty rows and deleting spaces in occupied cells

I'm looking for a way to loop through the third column of each row of a table.
If that cell is blank, it should shade the entire row
If that cell is occupied, it should look for any spaces and replace all spaces with a single # (for example 123 abc becomes 123#abc).
It should not run on the header row of the table.
Some random items-
the worksheet name is Quote
table name is QuoteTable
shading should be RGB(255, 248, 220)
The number of rows in the table will always vary, but the macro will always be checking the contents of the third column of the table which is named Model #.
Thanks for the responses, I will try each one, and in the meantime I came up with this--- which does everything except it highlights every single row from A-N not just the correct ones.
Public Sub ValidateSKUs()
Dim sMfrPN As String
Dim tbl1 As Range
Dim myCell As Range
Set tbl1 = Sheets("Quote").Range("QuoteTable")
For Each myCell In tbl1.Columns(3).Cells
If myCell.Value = "" Then
Sheets("Quote").Range("A" & myCell & ":N" & myCell).Interior.Color = RGB(255, 248, 220)
Sheets("Quote").Range("A" & myCell & ":N" & myCell).Interior.Pattern = xlSolid
Else
sMfrPN = CleanUpPN(myCell)
myCell = sMfrPN
End If
Next
End Sub
Public Function CleanUpPN(ByVal sMfrPN As String) As String
Dim sPN As String
'Trim trailing spaces
sPN = Trim(sMfrPN)
'Replace space with #
sPN = Replace(sPN, " ", "#")
'remove multiple # (e.g. ##)
Do Until InStr(1, sPN, "##") = 0
sPN = Replace(sPN, "##", "#")
Loop
CleanUpPN = sPN
End Function
VBA coding for a structured table can be a pain. You can either deal with the table as a ListObject object or Set a Range object variable to the .DataBodyRange property and deal with the cell addresses as you would with any other worksheet reference.
Sub fix_model_no()
Dim mn As Range
With Worksheets("Sheet1") '<~~ set this properly!
With .ListObjects("QuoteTable")
For Each mn In Range("QuoteTable[Model '#]")
If Len(Trim(mn.Value2)) Then
Intersect(.DataBodyRange, Rows(mn.Row)).Interior.ColorIndex = xlColorIndexNone
mn = Replace(Application.Trim(mn.Value2), Chr(32), Chr(35))
Else
mn.ClearContents
Intersect(.DataBodyRange, Rows(mn.Row)).Interior.ColorIndex = 3 'red
End If
Next mn
End With
End With
End Sub
The single tick in QuoteTable[Model '#] is necessary to reference the Model # column. Any reference to a ListObject table likes to know which worksheet the table resides on.
You may wish to consider Conditional Formatting for the row highlighting based upon the blank cells in column C.
      
Change "Z" to whatever column you require
Sub Oh_Ya()
Dim sh As Worksheet
Dim rng As Range, c As Range
Dim rws As Long, r
Set sh = Sheets("Quote")
With sh
rws = .Cells(.Rows.Count, "A").End(xlUp).Row
Set rng = .Range("C2:C" & rws)
For Each c In rng.Cells
c = Replace(c, " ", "#")
If c = "" Then
r = c.Row
Range("A" & r & ":Z" & r).Interior.Color = RGB(255, 248, 220)
End If
Next c
End With
End Sub

VBA - Delete rows that have the same ID and based on a Date

I am trying to build a VBA macro in order to delete rows that have the same ID AND contains a date before 01/01/2015. Please see the screenshot : (red rows have to be deleted).
I have started to build the following macro :
Sub Auto_Open()
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
'***** Variables declaration *****
Dim LastRow As Integer
Dim EventDate As String
Dim Col As New Collection
Dim itm
Dim i As Long
Dim CellVal As Variant
'***** Find the last row *****
LastRow = Range("A" & Rows.Count).End(xlUp).Row
'***** Conditional Formatting for Statut *****
For i = 2 To LastRow
CellVal = Sheets("DataSet1").Range("A" & i).Value
On Error Resume Next
Col.Add CellVal, Chr(34) & CellVal & Chr(34)
On Error GoTo 0
Next i
For Each itm In Col
Debug.Print itm
Next
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
End Sub
Unfortunately it only lists the different IDs and I don't know how to select the rows I want to delete.
Could you advise?
Thank you,
Damien
Why don't you store the row number i when finding a row to delete?
Col.Add CellVal, Chr(34) & CellVal & Chr(34), i
Actually, you're half way through. In that loop, determine if the ID and date match your pattern, and if so, store the rownumber. Then in a second loop, looping from end to start (step -1), delete each row in the collection.
Edit:
Keep things simple. Do not use references to objects, but objects. "Make it work, make it right, make it fast" - in that order. This is what remains from your code when it does what is necessary:
For Row = 2 To LastRow
CellDate = CDate(S.Cells(i, 2).Value)
If (CellDate < TestDate) Then
If Not D.Exists(S.Cells(i, 1).Value) Then
D.Add S.Cells(i, 1).Value
Else ' is duplicate!
willdeleted.Add Row
End If
End If
Next Row
For Row = willdeleted.Count To 1 Step -1
Rows(willdeleted(i)).EntireRow.Delete
Next Row
And do NOT use a Dictionary for the row numbers (willdeleted)! A simple list will do, either an Array() or a Collection. Dictionaries do not keep the order in which elements were added. The list of rownumbers to delete must be sorted, from lowest to highest, in order to be able to delete rows from the bottom of the table up.
I changed some of code and added codes of mine. Please examine codes and please say what you think. if you this couldnt not solve your problem, please give more information.
Sub Auto_Open()
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
'***** Variables declaration *****
Dim LastRow As Integer
Dim EventDate As String
Dim Col As New Collection
Dim itm
Dim i As Long
Dim CellVal As Variant
Dim CellObj As Range
'to check if cell exist in list earlier
Dim D As Dictionary
' if same key exist in list then add it to willbedeleted list
Dim willdeleted As Dictionary
Dim S As Worksheet
Dim Cnt As Integer
Dim CellDate As Date
Dim TestDate As Date
'***** Find the last row *****
LastRow = Range("A1").End(xlDown).Row
Set S = Worksheets("Dataset1")
Set D = New Dictionary
Set willdeleted = New Dictionary
TestDate = CDate("01/01/2015")
'***** Conditional Formatting for Statut *****
For i = 2 To LastRow
Set CellObj = S.Cells(i, 1)
On Error Resume Next
CellDate = CDate(CellObj.Offset(0, 1).Value)
If (CellDate < TestDate) Then
If (Not D.Exists(CellObj.Value)) Then
D.Add CellObj.Value, CellObj
Else
willdeleted.Add CellObj.Address(RowAbsolute:=True, ColumnAbsolute:=True), CellObj
End If
End If
On Error GoTo 0
Next i
a = willdeleted.Items
For i = 0 To willdeleted.Count - 1
CellObj = a(i)
Debug.Print "#" & CellObj.Row & " row deleted.. : " & CellObj.Value & ", " & CellObj.Offset(0, 1).Value
Rows(CellObj.Row).EntireRow.Delete
Next i
End Sub

Excel Moving duplicate values to new sheet

I have compiled this code from bit and pieces I have found - I am by no means an expert - more of an eager student - This code works for me but now I need to keep the first occurrence of the duplicate row to stay on the original worksheet and move only the subsequent occurrence(s) to the newly created sheet.
I am willing to redo all the code if needed but would prefer to modify the existing vba for the sake of time
Sub moveduplicates
'***************************************************************
'** This proc expects you to select all the cells in a single **
'** column that you want to check for duplicates in. If dup- **
'** licates are found, the entire row will be copied to the **
'** predetermined sheet. **
'***************************************************************
Set Rng = ActiveCell
'Sticky_Selection()
Dim s As Range
Set s = Selection
Cells.EntireColumn.Hidden = False
Worksheets.Add(After:=Worksheets(Worksheets.Count)).Name = "Duplicate Values"
Sheets("Data").Select
Range("A2").Select
Range(Selection, Selection.End(xlToRight)).Select
Selection.Copy
Sheets("Duplicate Values").Select
Range("A1").Select
ActiveSheet.Paste
s.Parent.Activate
s.Select 'NOT Activate - possibly more than one cell!
Dim ShO As Worksheet
Dim Rng1 As Range
Dim pRow As Integer
Dim c As Range, cTmp As Range
Dim found
Dim Addresses() As String
Dim a() As String
Dim p2 As Integer
Dim tfFlag As Boolean, sTmp As Variant
Set ShO = Worksheets("Duplicate Values") 'You can change this to whatever worksheet name you want the duplicates in Set Rng1 = Application.InputBox("Select a range", "Obtain Range Object", Type:=8)
MsgBox "The cells selected were " & Rng.Address 'Rng1 is all the currently selected cells
pRow = 2 'This is the first row in our output sheet that will be used to record duplicates
ReDim a(0) 'Initialize our array that holds found values
For Each c In Rng1.Cells 'Cycle through each cell in our selected range
ReDim Addresses(0) 'This array holds the cell address for our duplicates.
'We will reset the array each time we move to the next cell
Now check the array of already found duplicates.
If the current value is already there skip to next value
tfFlag = False
For Each sTmp In a
If CStr(c.Value) = sTmp Or CStr(c.Value) = "xXDeleteXx" Then 'We've already done this value, move on
tfFlag = True
Exit For
End If
Next
If Not tfFlag Then 'Remember the flag is true when we have already located the
'duplicates for this value, so skip to next value
With Rng1
Set found = .Find(c.Value, LookIn:=xlValues) 'Search entire selected range for value
If Not found Is Nothing Then 'Found it
Addresses(0) = found.Address 'Record the address we found it
Do 'Now keep finding occurances of it
Set found = .FindNext(found)
If found.Address <> Addresses(0) Then
ReDim Preserve Addresses(UBound(Addresses) + 1)
Addresses(UBound(Addresses)) = found.Address
End If
Loop While Not found Is Nothing And found.Address <> Addresses(0) 'Until we get back to the original address
If UBound(Addresses) > 0 Then 'We Found Duplicates
a(UBound(a)) = c.Value 'Record the value we found a duplicate for in an array
'ReDim Preserve a(UBound(a) + 1) 'add an empty spot to the array for next value
'ShO.Range("A" & pRow).Value = "Duplicate Rows for Value " & c.Value & _
" in Column " & c.Column & " on original sheet" 'Add a label row
'pRow = pRow + 1 'Increment to the next row
For p2 = UBound(Addresses) To 0 Step -1 'Cycle through the duplicate addresses
Set cTmp = Rng1.Worksheet.Range(Addresses(p2)) 'we just want to easily get the correct row to copy
Rng1.Worksheet.Rows(cTmp.Row).Copy ShO.Rows(pRow) 'Copy form orig to duplicates sheet
cTmp.Value = "xXDeleteXx" 'Mark for Delete the original row
pRow = pRow + 1 'Increment row counter
Next p2
'Row = pRow + 1 'This increment will give us a blank row between sets of duplicates
End If
End If
End With
End If
Next
'Now go delete all the marked rows
Do
tfFlag = False
For Each c In Rng1
If c.Value = "xXDeleteXx" Then
Rng1.Worksheet.Rows(c.Row).Delete (xlShiftUp)
tfFlag = True
End If
Next
Loop Until tfFlag = False
'AutoFit Every Worksheet Column in a Workbook
For Each sht In ThisWorkbook.Worksheets
sht.Cells.EntireColumn.AutoFit
Next sht
Application.Goto Rng
End
End Sub
Thank you very much for your time and consideration
You can use a scripting Dictionary object to keep track of duplicates:
Sub RemoveDups()
Dim c As Range, dict, rngDel As Range, rw As Long
Dim wb As Workbook
Dim shtDups As Worksheet
Dim rng1 As Range
Set rng1 = Selection 'assuming you've selected a single column of values
' from which you want to remove dups
Set wb = ActiveWorkbook
Set shtDups = wb.Worksheets.Add( _
after:=wb.Worksheets(wb.Worksheets.Count))
shtDups.Name = "Duplicate Values"
With rng1.Parent
.Range(.Range("A2"), .Range("A2").End(xlToRight)).Copy _
shtDups.Range("A1")
End With
rw = 2
Set dict = CreateObject("scripting.dictionary")
For Each c In rng1.Cells
'already seen this value?
If dict.exists(c.Value) Then
c.EntireRow.Copy shtDups.Cells(rw, 1)
rw = rw + 1
'add row to "delete" range
If rngDel Is Nothing Then
Set rngDel = c
Else
Set rngDel = Application.Union(c, rngDel)
End If
Else
'first time for this value - add to dictionary
dict.Add c.Value, 1
End If
Next c
'delete all duplicate rows (if found)
If Not rngDel Is Nothing Then
rngDel.EntireRow.Delete
End If
End Sub
Another enthusiastic amateur here!
Not really answering your question, but here is a little function I use for removing duplicate rows:
Sub RemoveDupes(TempWB As Workbook, TargetSheet As String, ConcatCols As String, DeleteTF As Boolean)
Dim Counter As Integer
Dim Formula As String
Dim RowCount As Integer
Dim StartingCol As String
Dim CurrentRow As Integer
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Remove duplicate rows on a worksheet '
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Prerequisites:
' - Data needs to start # A1
' - Data has headings in row 1
' determine number of rows to be processed
RowCount = TempWB.Sheets(TargetSheet).Cells(TempWB.Sheets(TargetSheet).Rows.Count, "A").End(xlUp).Row
' insert a column to hold the calculate unique key
TempWB.Sheets(TargetSheet).Columns("A:A").Insert Shift:=xlToRight, CopyOrigin:=xlFormatFromLeftOrAbove
' add a heading
TempWB.Sheets(TargetSheet).Cells(1, 1).Value = "Duplication Check"
' insert the unique key formula
For CurrentRow = 2 To RowCount
' start the formula string
Formula = "="
' construct the formula
For Counter = 1 To Len(ConcatCols)
' if we are on the last element, dont add another '&'
If Counter = Len(ConcatCols) Then
Formula = Formula & AddLetter(Mid(ConcatCols, Counter, 1)) & CurrentRow
Else
Formula = Formula & AddLetter(Mid(ConcatCols, Counter, 1)) & CurrentRow & "&"
End If
' Debug.Print Mid(ConcatCols, Counter, 1)'Next
' next element!
Next
' insert the newly constructed formula
TempWB.Sheets(TargetSheet).Cells(CurrentRow, "A").Formula = Formula
' next row
Next
' unfortunately we need to use explicit selection here *sigh*
TempWB.Sheets(TargetSheet).Activate
' to select the range we are going to test
TempWB.Sheets(TargetSheet).Range("A2:A" & TempWB.Sheets(TargetSheet).Cells(Rows.Count, "A").End(xlUp).Row).Select
' clock down the list flagging each dupe by changing the text color
Dim d As Object, e
Set d = CreateObject("scripting.dictionary")
For Each e In Intersect(Columns(ActiveCell.Column), ActiveSheet.UsedRange)
If e.Value <> vbNullString Then
If Not d.exists(e.Value) Then d(e.Value) = 1 Else _
e.Font.ColorIndex = 4
End If
Next
' if the delete flag is set...
If DeleteTF Then
' then go down the list deleting rows...
For CurrentRow = RowCount To 2 Step -1
' if the row has been highlighted, its time to go...
If TempWB.Sheets(TargetSheet).Cells(CurrentRow, "A").Font.ColorIndex = 4 Then
TempWB.Sheets(TargetSheet).Cells(CurrentRow, "A").EntireRow.Delete
End If
Next
' If we are deleting rows, remove the column just like we were never here
TempWB.Sheets(TargetSheet).Cells(1, "A").EntireColumn.Delete
End If
End Sub
Function AddLetter(Letter As String)
' gives you the next letter
AddLetter = Split(Cells(, Range(Letter & 1).Column + 1).Address, "$")(1)
End Function
When I get a sec I will have a go adapting this to your requirements...
This will search a specified column for duplicates, copying subsequent duplicates entries to Sheet2 and then remove them from Sheet1.
I've used the Scripting Dictionary too but you will need to add a reference to "Microsoft Scripting Runtime" for the code to work as-is. (Adding the reference will help if you want to learn about dictionaries since it adds the Dictionary to Intellitype code completion stuff)
Sub Main()
Dim SearchColumn As Integer: SearchColumn = 2 ' column to search for duplicates
Dim Source As Worksheet: Set Source = ThisWorkbook.Worksheets("Sheet1")
Dim Duplicates As Worksheet: Set Duplicates = ThisWorkbook.Worksheets("Sheet2")
Dim List As Dictionary: Set List = New Dictionary ' used to hold the first instance of unique items
Dim Data As Variant ' holds a copy of the column you want to search
Dim Count As Integer ' hold the size of said column
Dim Index As Integer ' iterator for data
Dim Item As String ' holds the current item
Count = Source.Cells(Source.Rows.Count, SearchColumn).End(xlUp).Row
Set Data = Source.Range(Source.Cells(1, SearchColumn).Address, Source.Cells(Count, SearchColumn).Address)
Application.ScreenUpdating = False
' first loop, find unique items and copy duplicates
For Index = 1 To Count
Item = Data(Index, 1)
If List.Exists(Item) = False Then
' add the item to our dictionary of items
List.Add Item, Index
Else
' add item to duplicates sheet as its a duplicate
Source.Rows(Index).Copy
Duplicates.Rows(1).Insert xlShiftDown
End If
Next Index
' second loop, remove duplicates from original sheet
For Index = Count To 1 Step -1
Item = Data(Index, 1)
If List.Exists(Item) Then
If Not List(Item) = Index Then
' the item is a duplicate and needs to be removed
Source.Rows(Index).Delete
End If
End If
Next Index
Application.ScreenUpdating = True
End Sub

Concatenate columns(user selected) and replace them with new column

I'm not an advanced VBA programmer. I'm working on an excel macro which will allow me to select a range(using input box) to clean the data(makes consistent with mySQL schema) on worksheet. I get this file from anther team and
1.) the order of columns is not fixed
2) levels of categories(there are few columns for categories like level1 level2 etc.) can be anything between 3-10.
I want to concatenate the columns for categories(in image level 1, level 2 etc.) using | as a separator and put the values in first category column(level1) while deleting remaining columns(level 2, level 3...[level 10]).
I removed some code from the end to reduce the length here but it still makes sense:
Sub cleanData()
Dim rngMyrange As Range
Dim cell As Range
On Error Resume Next
Do
'Cleans Status column
Set rngMyrange = Application.InputBox _
(Prompt:="Select Status column", Type:=8)
On Error GoTo 0
'Is a range selected? Exit sub if not selected
If rngMyrange Is Nothing Then
End
Else
Exit Do
End If
Loop
With rngMyrange 'with the range just selected
.Replace What:="Dead", Replacement:="Inactive", SearchOrder:=xlByColumns, MatchCase:=False
'I do more replace stuff here
End With
rngMyrange.Cells(1, 1) = "Status"
Do
'Concatenates Category Columns
Set rngMyrange = Application.InputBox _
(Prompt:="Select category columns", Type:=8)
On Error GoTo 0
'Is a range selected? Exit sub if not selected
If rngMyrange Is Nothing Then
End
Else
Exit Do
End If
Loop
With rngMyrange 'with the range just selected
'Need to concatenate the selected columns(row wise)
End With
rngMyrange.Cells(1, 1) = "Categories"
End Sub
Please do not suggest a UDF, I want to do this with macro. I must do this on files before importing them on SQL database, so a macro will be handy. Please ask if I failed to mention anything else.
EDIT: Image attached for illustration
UPDATE:
I now have a working code with help from vaskov17 on mrexcel but it does not delete the columns from where the levels are picked-level 2, level 3...etc. to shift next columns to left and the major challenge for me is to implement that code in my existing macro using range type instead of long type. I do not want to enter start column and finish column separately, instead I should be able to select range like in my original macro. Code for that macro is below, please help me:
Sub Main()
Dim start As Long
Dim finish As Long
Dim c As Long
Dim r As Long
Dim txt As String
start = InputBox("Enter start column:")
finish = InputBox("Enter ending column:")
For r = 2 To Cells(Rows.Count, "A").End(xlUp).Row
For c = start To finish
If Cells(r, c).Text <> "" Then
txt = txt & Cells(r, c).Text & "|"
Cells(r, c).Clear
End If
Next
If Right(txt, 1) = "|" Then
txt = Left(txt, Len(txt) - 1)
End If
Cells(r, start) = txt
txt = ""
Next
End Sub
I have removed the inputbox for selection of the category columns. Since they are always named Level x»y it makes it easier to find them automatically. That's why added a FindColumns() Sub to your code. It assigns the first fCol and last lCol Category column to global variables.
The ConcatenateColumns() concatenates cells in each row using "|" as separator.
The DeleteColumns() deletes the other columns
Cells(1, fCol).Value = "Category renames Level 1 to Category and Columns.AutoFit resizes all columns widths to fit the text.
Code:
Option Explicit
Dim fCol As Long, lCol As Long
Sub cleanData()
Dim rngMyrange As Range
Dim cell As Range
On Error Resume Next
Do
'Cleans Status column
Set rngMyrange = Application.InputBox _
(Prompt:="Select Status column", Type:=8)
On Error GoTo 0
'Is a range selected? Exit sub if not selected
If rngMyrange Is Nothing Then
End
Else
Exit Do
End If
Loop
With rngMyrange 'with the range just selected
.Replace What:="Dead", Replacement:="Inactive", SearchOrder:=xlByColumns, MatchCase:=False
'I do more replace stuff here
End With
rngMyrange.Cells(1, 1) = "Status"
' Concatenate Category Columns
FindColumns
ConcatenateColumns
DeleteColumns
Cells(1, fCol).Value = "Category"
Columns.AutoFit
End Sub
Private Sub FindColumns()
Dim ws As Worksheet
Set ws = ActiveSheet
Dim i As Long, j As Long
For i = 1 To ws.Cells(1, Columns.Count).End(xlToLeft).Column
If StrComp(ws.Cells(1, i).Text, "Level 1", vbTextCompare) = 0 Then
For j = i To ws.Cells(1, Columns.Count).End(xlToLeft).Column
If InStr(1, ws.Cells(1, j).Text, "Level", vbTextCompare) Then
lCol = j
End If
Next j
fCol = i
Exit Sub
End If
Next i
End Sub
Private Sub ConcatenateColumns()
Dim rng As Range
Dim i As Long, j As Long
For i = 2 To Cells(Rows.Count, fCol).End(xlUp).Row
Set rng = Cells(i, fCol)
For j = fCol + 1 To lCol
rng = rng & "|" & Cells(i, j)
Next j
rng = "|" & rng & "|"
Set rng = Nothing
Next i
End Sub
Private Sub DeleteColumns()
Dim i As Long
For i = lCol To fCol + 1 Step -1
Columns(i).Delete Shift:=xlToLeft
Next i
End Sub