Delete rows in MS Word if some specific cells are empty - vba

So I have this VBA Code to delete the rows in Word tables if the 6th cells of those tables are empty. But the thing is not every table has 6 columns so this code deletes all my tables with 5 columns or less. Can you guys help me out to add a function that counts the number of columns if it's smaller than 6 then exit sub? Sorry for my bad English.
Sub BCPISADeleteEmptyRows()
Dim tbl As Table, cel As Cell
Dim i As Long, j As Long, n As Long, fEmpty As Boolean
Application.ScreenUpdating = False
With ActiveDocument
For Each tbl In .Tables
n = tbl.Rows.Count
For i = n To 1 Step -1
fEmpty = True
For j = 6 To tbl.Rows(i).Cells.Count
Set cel = tbl.Rows(i).Cells(j)
If Len(Trim(cel.Range.Text)) > 2 Then
fEmpty = False
Exit For
End If
Next j
If fEmpty = True Then tbl.Rows(i).Delete
Next i
Next tbl
End With
Set cel = Nothing: Set tbl = Nothing
Application.ScreenUpdating = True
End Sub

For example:
Sub BCPISADeleteEmptyRows()
Application.ScreenUpdating = False
Dim Tbl As Table, r As Long
For Each Tbl In ActiveDocument.Tables
With Tbl
If .Columns.Count > 5 Then
For r = .Rows.Count To 2 Step -1
If Len(Trim(.Cell(r, 6).Range.Text)) = 2 Then .Rows(r).Delete
Next
End If
End With
Next
Application.ScreenUpdating = True
End Sub

Related

How to split cells containing "hard returns"

How to split cells containing "hard returns" (paragraph marks)
as in the picture below?
the desired result:
Here is my code
Sub SplitCells()
'
Dim selT As String
Dim arr
Dim i As Integer
selT = selection.Range.Text
arr = Split(selT, ChrW(13))
selection.Range.Cut
selection.Cells.Split NumRows:=UBound(arr) + 1, NumColumns:=1, MergeBeforeSplit:=False
selection.MoveDown wdLine, 1
For i = UBound(arr) To 0 Step -1
selection.MoveUp wdLine, 1
selection.TypeText arr(i)
Next
End Sub
It works, but I feel this code is clumsy and hope someone can tell me a elegant way.
Try the following; it will split all affected rows in the selected table.
Sub Demo()
Application.ScreenUpdating = False
Dim Tbl As Table, RngA As Range, RngB As Range
Dim i As Long, l As Long, r As Long, c As Long, p As Long
With Selection
If .Information(wdWithInTable) = False Then
MsgBox "Please select a table/cell and try again."
Exit Sub
End If
Set Tbl = .Tables(1)
With Tbl
l = .Columns.Count
For i = .Range.Cells.Count To 1 Step -1
With .Range.Cells(i).Range
Do While .Characters.Last.Previous = vbCr
.Characters.Last.Previous = vbNullString
Loop
End With
Next
For r = .Rows.Count To 1 Step -1
With .Rows(r)
If .Range.Paragraphs.Count > l + 1 Then
For c = 1 To .Cells.Count
If .Cells(c).Range.Paragraphs.Count > p Then p = .Cells(c).Range.Paragraphs.Count
Next
If p > 1 Then .Cells.Split Numrows:=p, Numcolumns:=1, MergeBeforeSplit:=False
For c = 1 To .Cells.Count
Set RngA = .Cells(c).Range
If RngA.Paragraphs.Count > 1 Then
For p = RngA.Paragraphs.Count To 2 Step -1
Set RngB = RngA.Paragraphs(p).Range
RngB.End = RngB.End - 1
If Len(RngB.Text) > 0 Then
With Tbl.Cell(r + p - 1, c).Range
.FormattedText = RngB.FormattedText
RngB.Delete
End With
End If
RngA.Paragraphs(p - 1).Range.Characters.Last = vbNullString
Next
End If
Next
End If
End With
Next
End With
End With
Application.ScreenUpdating = True
End Sub
Compared to your approach, the above code also has the advantage of preserving any text formatting.
There's nothing wrong with it, really. In order to move up/down in a table with split/merged cells you need Selection...
Here's code that uses the object model instead of Selection as much as possible. But I'm not sure I'd term it "more elegant" or "less clumsy". Possibly, it's more self-documenting since it uses Word objects where ever possible.
One change I did make is to test whether the selection is in a table before doing anything. If the user would forget to select a cell without such a test a cryptic error messsage would display, which is always annoying...
Sub SplitCells()
'
Dim cel As Word.Cell
Dim selT As String
Dim arr
Dim i As Integer
Dim nrCells As Long
If Selection.Information(wdWithInTable) Then
Set cel = Selection.Cells(1)
selT = cel.Range.Text
arr = Split(selT, ChrW(13))
nrCells = UBound(arr)
cel.Range.Delete
cel.Split NumRows:=nrCells, NumColumns:=1 ', _
'MergeBeforeSplit:=False
cel.Select
Selection.MoveDown wdLine, nrCells - 1
For i = nrCells - 1 To 0 Step -1
Set cel = Selection.Cells(1)
cel.Range.Text = arr(i)
cel.Select
Selection.MoveUp wdLine, 1
Next
Else
MsgBox "Please select a table cell and try again."
End If
End Sub

Delete entire Row with zeroes apply to all worksheets

I have VBA code that works to delete entire row when there is an absolute zero value in one a cell column but, I am not able to figure out how to update code to apply to all worksheets (there are 20 Sheets in my workbook):
Can someone help with syntax how to update this code to apply to all worksheets in the workbook.
Sub IfandthenDelete_Button3_Click()
Dim lRow As Long
Dim i As Long
lRow = 3000
Application.ScreenUpdating = False
For i = lRow To 1 Step -1
If Cells(i, 1) = 0 Then
Rows(i).Delete
End If
Next
Application.ScreenUpdating = False
End Sub
You need one more for loop for that.
Sub WorksheetLoop()
Dim wsCount As Integer
Dim j As Integer
Dim lRow As Long
Dim i As Long
lRow = 3000
wsCount = ActiveWorkbook.Worksheets.Count
For j = 1 To wsCount
For i = lRow To 1 Step -1
If ActiveWorkbook.Worksheets(j).Cells(i, 1) = 0 Then
ActiveWorkbook.Worksheets(j).Rows(i).Delete
End If
Next
Next j
End Sub

Having Problems to perform formulas in a range

I got this macro from this site but after running it the seems to behaving abnormally. Macro is running good and removing all blanks and empty rows and column but after running it I'm having problem to perform other formulas like plus minus in a range.
My code:
Sub RemoveBlankRowsColumns()
'PURPOSE: Remove blank rows or columns contained in the spreadsheets UsedRange
Dim rng As Range
Dim rngDelete As Range
Dim RowCount As Long, ColCount As Long
Dim EmptyTest As Boolean, StopAtData As Boolean
Dim RowDeleteCount As Long, ColDeleteCount As Long
Dim x As Long
Dim UserAnswer As Variant
'Analyze the UsedRange
Set rng = ActiveSheet.UsedRange
rng.Select
RowCount = rng.Rows.Count
ColCount = rng.Columns.Count
DeleteCount = 0
'Optimize Code
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
Application.EnableEvents = False
'Loop Through Rows & Accumulate Rows to Delete
For x = RowCount To 1 Step -1
'Is Row Not Empty?
If Application.WorksheetFunction.CountA(rng.Rows(x)) <> 0 Then
If StopAtData = True Then Exit For
Else
If rngDelete Is Nothing Then Set rngDelete = rng.Rows(x)
Set rngDelete = Union(rngDelete, rng.Rows(x))
RowDeleteCount = RowDeleteCount + 1
End If
Next x
'Delete Rows (if necessary)
If Not rngDelete Is Nothing Then
rngDelete.EntireRow.Delete Shift:=xlUp
Set rngDelete = Nothing
End If
'Loop Through Columns & Accumulate Columns to Delete
For x = ColCount To 1 Step -1
'Is Column Not Empty?
If Application.WorksheetFunction.CountA(rng.Columns(x)) <> 0 Then
If StopAtData = True Then Exit For
Else
If rngDelete Is Nothing Then Set rngDelete = rng.Columns(x)
Set rngDelete = Union(rngDelete, rng.Columns(x))
ColDeleteCount = ColDeleteCount + 1
End If
Next x
'Delete Columns (if necessary)
If Not rngDelete Is Nothing Then
rngDelete.Select
rngDelete.EntireColumn.Delete
End If
'Refresh UsedRange (if necessary)
If RowDeleteCount + ColDeleteCount > 0 Then
ActiveSheet.UsedRange
End If
End Sub
Condensed code:
Sub RemoveBlankRowsColumns()
'PURPOSE: Remove blank rows or columns contained in the spreadsheets UsedRange
Dim RowCount As Long, ColCount As Long, x As Long
'Dim EmptyTest As Boolean, StopAtData As Boolean
Dim RowDeleteCount As Long: RowDeleteCount = 0
Dim ColDeleteCount As Long: ColDeleteCount = 0
Dim DeleteCount As Long: DeleteCount = 0
'Dim UserAnswer As Variant
On Error GoTo ExitSub
With ActiveSheet.UsedRange
RowCount = .Rows.Count
ColCount = .Columns.Count
'Optimize Code
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
Application.EnableEvents = False
'Loop Through Rows & Delete
For x = RowCount To 1 Step -1
'Is Row Not Empty?
If Application.WorksheetFunction.CountA(.Rows(x)) <> 0 Then
If StopAtData = True Then Exit For
Else
.Rows(x).EntireRow.Delete Shift:=xlUp
RowDeleteCount = RowDeleteCount + 1
End If
Next x
'Loop Through Columns & Delete
For x = ColCount To 1 Step -1
'Is Column Not Empty?
If Application.WorksheetFunction.CountA(.Columns(x)) <> 0 Then
If StopAtData = True Then Exit For
Else
.Columns(x).EntireColumn.Delete Shift:=xlLeft
ColDeleteCount = ColDeleteCount + 1
End If
Next x
DeleteCount = RowDeleteCount + ColDeleteCount
End With
ExitSub:
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
Application.EnableEvents = True
End Sub

Comparing Column's with other columns with vba excel

I have the following problem to solve.
I have an excel sheet with 3 columns and 29000 rows.
Column a is an index number.
Column b is an id number.
Column c is a number which points to an index of column a
So if column c is 200. I need to go to column a 200 and take it's column b id and put it on the same row as the column c index.
The purpose of this is to link the id number of two items, who are linked by this column c.
(I hope I am making sense :/ )
So I have been trying to code this in VBA. At the moment I am using a nested for loop, but as you can imagine, the run time is pretty long....
dim i as integer
dim v as integer
dim temp as integer
i = 1
v=1
for i = 1 to 29000
if cells(i,3).value > 0 then
temp = cells(i,3).Value
cells(i,5).value = cells(1,2).value
for v = 1 to 29000
if cells(v,1).value = temp and cells(i,5).value <> cells(v,2).value then
cells(i,6).value = cells(v,2).value
end if
next
end if
next
So it does work and performs what I want, but the run time is just too long. Any ideas how to streamline the program?
I am pretty new to vba and programming in general.
Thanks in advance
Untested, but compiled OK
Sub Test()
Dim dict As Object
Dim i As Long
Dim temp As Long
Dim sht As Worksheet
Dim oldcalc
Set sht = ActiveSheet
Set dict = GetMap(sht.Range("A1:B29000"))
With Application
.ScreenUpdating = False
oldcalc = .Calculation
.Calculation = xlCalculationManual
End With
For i = 1 To 29000
If Cells(i, 3).Value > 0 Then
temp = Cells(i, 3).Value
Cells(i, 5).Value = Cells(1, 2).Value
If dict.exists(temp) Then
If sht.Cells(i, 5).Value <> dict(temp) Then
sht.Cells(i, 6).Value = dict(temp)
End If
End If
End If
Next
With Application
.ScreenUpdating = True
.Calculation = oldcalc 'restore previous setting
End With
End Sub
Function GetMap(rng As Range) As Object
Dim rv As Object, arr, r As Long, numRows As Long
Set rv = CreateObject("scripting.dictionary") 'EDITED to add Set
arr = rng.Value
numRows = UBound(arr, 1)
For r = 1 To numRows
If Not rv.exists(arr(r, 1)) Then
rv.Add arr(r, 1), arr(r, 2)
End If
Next r
Set GetMap = rv
End Function

Move certain row of data into column

If I have all data in one very long column like this:
A
B
C
1
2
3
D
E
F
4
5
6
G
H
I
7
8
9
Is it possible to move data like this?
Column1 Column2 Column3 Column4 Column5 Column6
A B C 1 2 3
D E F 4 5 6
G H I 7 8 9
I tried paste special+transpose , but I have more than 10 thousands records , so it will take me too much time in using this method.
I'm new in excel and macro , thank you very much.
Edit:
I even tried to transpose all data into many columns then select the column I want to make them all into one column with this macro:
Sub OneColumn()
' Jason Morin as amended by Doug Glancy
' http://makeashorterlink.com/?M19F26516
''''''''''''''''''''''''''''''''''''''''''
'Macro to copy columns of variable length
'into 1 continuous column in a new sheet
''''''''''''''''''''''''''''''''''''''''''
Dim from_lastcol As Long
Dim from_lastrow As Long
Dim to_lastrow As Long
Dim from_colndx As Long
Dim ws_from As Worksheet, ws_to As Worksheet
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
Set ws_from = ActiveWorkbook.ActiveSheet
from_lastcol = ws_from.Cells(1, Columns.Count).End(xlToLeft).Column
'Turn error checking off so if no "AllData" trying to delete doesn't generate Error
On Error Resume Next
'so not prompted to confirm delete
Application.DisplayAlerts = False
'Delete if already exists so don't get error
ActiveWorkbook.Worksheets("AllData").Delete
Application.DisplayAlerts = True
'turn error checking back on
On Error GoTo 0
'since you refer to "AllData" throughout
Set ws_to = Worksheets.Add
ws_to.Name = "AllData"
For from_colndx = 1 To from_lastcol
from_lastrow = ws_from.Cells(Rows.Count, from_colndx).End(xlUp).Row
'If you're going to exceed 65536 rows
If from_lastrow + ws_to.Cells(Rows.Count, 1).End(xlUp).Row <= 65536 Then
to_lastrow = ws_to.Cells(Rows.Count, 1).End(xlUp).Row
Else
MsgBox "This time you've gone to far"
Exit Sub
End If
ws_from.Range(ws_from.Cells(1, from_colndx), ws_from.Cells(from_lastrow, _
from_colndx)).Copy ws_to.Cells(to_lastrow + 1, 1)
Next
' this deletes any blank rows
ws_to.Columns(1).SpecialCells(xlCellTypeBlanks).EntireRow.Delete
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
End Sub
But it will just join all column into one but not the column selected.
For Remou reference:
Here is the output:
A D G
B E H
C F I
1 4 7
2 5 8
3 6 9
You can look at something in these lines:
Sub TransposeColumn()
Dim rng As Range
Dim ws As Worksheet
Set rng = Worksheets("Input").UsedRange
Set ws = Worksheets("Output")
j = 1
k = 1
For i = 1 To rng.Rows.Count
If rng.Cells(i, 1) = vbNullString Then
j = j + 1
k = 1
Else
''ws.Cells(k, j) = rng.Cells(i, 1)
''EDIT
ws.Cells(j, k) = rng.Cells(i, 1)
k = k + 1
End If
Next
End Sub
This is how I do the same thing... it creates the new table in column C over...based on your example that there is a blank cell between each group of data:
Sub TransposeGroups()
Dim RNG As Range, Grp As Long, NR As Long
Set RNG = Range("A:A").SpecialCells(xlConstants)
NR = 1
For Grp = 1 To RNG.Areas.Count
RNG.Areas(Grp).Copy
Range("C" & NR).PasteSpecial xlPasteAll, Transpose:=True
NR = NR + 1
Next Grp
End Sub
This should work for any length of data and "groups" of up to 8500 within the data.
This also uses the AREAS method, but this overcomes the groups limitation by using subgroups, so it should work with any size dataset.
Sub TransposeGroups2()
'Uses the AREAS method and will work on any size data set
'overcomes the limitation of areas by working in subgroups
Dim RNG As Range, rngSTART As Range, rngEND As Range
Dim LR As Long, NR As Long, SubGrp As Long, Itm As Long
LR = Range("A" & Rows.Count).End(xlUp).Row
NR = 1
SubGrp = 1
Set rngEND = Range("A" & SubGrp * 10000).End(xlUp)
Set RNG = Range("A1", rngEND).SpecialCells(xlConstants)
Do
For Itm = 1 To RNG.Areas.Count
RNG.Areas(Itm).Copy
Range("C" & NR).PasteSpecial xlPasteAll, Transpose:=True
NR = NR + 1
Next Itm
If rngEND.Row = LR Then Exit Do
Set rngSTART = rngEND.Offset(1)
SubGrp = SubGrp + 1
Set rngEND = Range("A" & (SubGrp * 10000)).End(xlUp)
Set RNG = Range(rngSTART, rngEND).SpecialCells(xlConstants)
Loop
End Sub