VBA Snippets to Delete Rows in Excel

I regularly use simple macros to delete blank rows in my excel spreadsheets and there are loads of examples on internet forums.

Screen shot 2009-09-05 at 15.59.57

I’ve recently had to recreate these delete row macros to install on a new computer and thought it would be useful to keep them filed here on the blog.

This first macro will delete any row in which the cell in the selected column is blank. So in this example, with column B selected, rows 4 & 7 will be deleted.

1
2
3
4
5
6
7
Sub DeleteRowOnBlankCell()
'Deletes entire row within the selected column where cell within selection is blank
Select column then run the macro
On Error Resume Next
Selection.EntireRow.SpecialCells(xlBlanks).EntireRow.Delete
On Error GoTo 0
End Sub

The following macro will only delete rows if the entire row is blank. Just select the area you want to evaluate and run the macro.

1
2
3
4
5
6
7
8
9
10
Sub DeleteBlankRows()

'Deletes the entire row within the selection provided the ENTIRE row is blank.
Dim i As Long
For i = Selection.Rows.Count To 1 Step -1
If WorksheetFunction.CountA(Selection.Rows(i)) = 0 Then
Selection.Rows(i).EntireRow.Delete
End If
Next i
End Sub

To use these macros just copy and paste them into a module within your personal macro workbook (press ALT F11 to open the VBA editor) which will make them available for use whenever excel is open. Sometimes the personal workbook doesn’t show up in the VBA editor and if this is the case I just record a new macro, select the option to save it in the personal workbook, make a few changes to a spreadsheet and stop recording. This will have the effect of creating a new module in  personal.xls, along with a fairly useless macro that can now be deleted.

Conditional Ranking in Excel – RankIF using SumProduct

I was hunting around for a RANKIF function yesterday so I could rank a load of hospitals in terms of their cost per procedure.

RankIF

Unfortunately RANKIF isn’t one of the available functions but I managed to achieve the same effect by utilising the SUMPRODUCT function.

I wrote a SUMPRODUCT tutorial some time ago indicating how the powerful function can act as a multi conditioned SUMIF formula but it seems it can also act as a multi conditioned RANKIF formula as well.

The formula I used to achieve the above ranking was:

=1+SUMPRODUCT(($B$2:$B$12=B2)*($C$2:$C$12>C2))

Copied down the column it will return the number of organisations for a given procedure which have costs higher than the selected row. Adding 1 to the result just ensures that the highest cost organisation starts with a rank of 1 rather than 0.

Excel CrossTab Table to Flat List

I had a query on my sumproduct tutorial that was effectively asking if I could work backwards from an excel crosstab or data table to get back to the simple flat list.

Converting a table like this:

sumproduct

Back to the data sheet like this:

sumproduct

If you didn’t have to do this sort of task very often you could get by with a pivot table solution and a few stages of formatting but it would only work if your data values were numbers that could be summed in the pivot.

If you need to convert Excel data tables (or crosstabs) into flat lists on a regular basis then you will need a macro.

I have prepared a workbook that demonstrates both the pivot table and macro solution and you can download it from here:
ExcelTabletoFlatList.xls

The following macro does the trick and utilises the VBA I introduced in my last post on consolidating worksheets, to determine the last used row and last used column.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
Sub CrossTabToList()

Dim wsCrossTab As Worksheet
Dim wsList As Worksheet
Dim iLastCol As Long
Dim iLastRow As Long
Dim iLastRowList As Long
Dim rngCTab As Range 'Used for range in Sheet1 cross tab sheet
Dim rngList As Range 'Destination range for the list
Dim I As Long

Set wsCrossTab = Worksheets("Sheet1")
Set wsList = Worksheets.Add

'Find the last row in Sheet1 with the cross tab
iLastRow = wsCrossTab.Cells(Rows.Count, "A").End(xlUp).Row

'Set the initial value for the row in the destination worksheet
iLastRowList = 2

'Find the last column in Sheet1 with the cross tab
iLastCol = wsCrossTab.Range("A1").End(xlToRight).Column

'Create a new sheet and set the heading titles
wsList.Range("A1:C1") = Array("NAME", "GRADE", "VALUE")

'Start looping through the cross tab data

For I = 2 To iLastRow

Set rngCTab = wsCrossTab.Range("A" & I) 'initial value A2
Set rngList = wsList.Range("A" & iLastRowList) 'initial value A2

'Copy individual names in Col A (A2 initially) into as many rows as there are data columns
'in the cross tab (less 1 for Col A).
rngCTab.Copy rngList.Resize(iLastCol - 1)

'Move up a I rows less one and across one column (using offset function) to select heading row. Copy.
rngCTab.Offset(-(I - 1), 1).Resize(, iLastCol - 1).Copy

'Paste transpose to columns in the list sheet alongside the names
rngList.Offset(0, 1).PasteSpecial Transpose:=True

'Staying on same row (2 initially) copy the data from the cross tab
rngCTab.Offset(, 1).Resize(, iLastCol - 1).Copy

'Past transpose as column in list sheet
rngList.Offset(0, 2).PasteSpecial Transpose:=True

'Set the new last row in list sheet to be just below the last name copied
iLastRowList = iLastRowList + (iLastCol - 1)

'increment I by 1
Next I

End Sub

Macros to Consolidate Worksheets

I’ve got a spreadsheet with tabs for each individual directorate. Within the tabs are tables with the same layout but different sizes (number of rows).

I want to group together all the used data on each tab and create a single consolidated sheet of continuous data.

Obviously I need a macro to copy and paste my data from each sheet but the tricky bit is selecting the relevant (or used) area in each sheet.

On my search around the interweb I found some really useful snippets of VBA code on the Ozgrid website which enable you to determine the last used row according to a number of different criteria and assign this to a variable such as “iLastRow”.

1
2
'find row before next blank cell in column A
iLastRow = Range("A1").End(xlDown).Row
1
2
'find last used row in column A
iLastRow = Cells(Rows.Count, "a").End(xlUp).Row
1
2
'find last used row on sheet
iLastRow = Cells.Find(what:="*", SearchOrder:=xlByRows, _SearchDirection:=xlPrevious).Row

It’s a simple step then to use this variable to define a range of used cells.

1
Range("A1:P" & iLastRow).Select

I’ve used the above techniques to consolidate my worksheets and here’s a copy of my working code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
Sub ConsolidateSheetsforSubForm()
' ConsolidateSheetsforSubForm Macro
' Copies used subform data in individual sheets and pastes into one sheet as continuous data

Sheets("Ap Table Sub Form").Select

'find last used row column a of Ap Table Sub Form sheet
ilastrowsubf = Cells(Rows.Count, "a").End(xlUp).Row

' Clear the existing data in the subform sheet
'specify location in subform to clear data
Range("a5:k" & ilastrowsubf).ClearContents

' Start selecting the data from Sheet S&M (LY)
Sheets("S&M (LY)").Select

' find last used row in column I
ilastrowsm = Cells(Rows.Count, "i").End(xlUp).Row

' use ilastrowsm variable to define range to copy in S&M sheet
Range("i4:s" & ilastrowsm).Copy

' specify location in subform to paste data
Sheets("Ap Table Sub Form").Select
Range("a5").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Sheets("K&R (BV)").Select

' find last used row in column I of K&R sheet
ilastrowkr = Cells(Rows.Count, "i").End(xlUp).Row

' use ilastrowkr variable to define range to copy in K&R sheet
Range("i4:s" & ilastrowkr).Copy
Sheets("Ap Table Sub Form").Select

' find first blank row in column a of Ap Table Sub Form sheet
ifirstblankrowsubf = (Cells(Rows.Count, "a").End(xlUp).Row) + 1

' specify location in subform to paste data
Range("a" & ifirstblankrowsubf).Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Sheets("OVERHEADS").Select

' find last used row in column I of OVERHEADS sheet
ilastrowover = Cells(Rows.Count, "i").End(xlUp).Row

' use ilastrowover variable to define range to copy in OVERHEADS sheet
Range("i4:s" & ilastrowover).Copy
Sheets("Ap Table Sub Form").Select

' find first blank row in column a of Ap Table Sub Form sheet
ifirstblankrowsubf = (Cells(Rows.Count, "a").End(xlUp).Row) + 1

' specify location in subform to paste data
Range("a" & ifirstblankrowsubf).Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Range("A5").Select
End Sub

You can do similar things in order to find the last column as well:

1
2
3
4
5
6
7
8
9
'find column before next blank cell in row 1
iLastColumn = Range("A1").End(xlToRight).Column

'find last used column in row 1
iLastColumn = Cells(Columns.Count, "a").End(xlToLeft).Column

'find last used column on sheet
iLastColumn = Cells.Find(what:="*", SearchOrder:=xlByColumns, _
SearchDirection:=xlPrevious).Column

Vlookup Errors – The Third Way

I’ve just published a post detailing a method of removing the errors returned by vlookup or hlookup utilising conditional formatting.

I had previously been using the double vlookup method to replace errors with blanks or zeros but then discovered that these excessive lookup functions had a tendency to bloat my spreadsheets.

While the conditional format method works, I can’t say that I particularly like it so I’ve been on the hunt for another method.

My first double lookup error hiding method looked like this:

=IF(ISERROR(VLOOKUP(L$7&$C13,’[WTE Apportionment Tables.xls]WTE APP TABLES SUB F’!$B:$K,9,0)),””,VLOOKUP(L$7&$C13,’[WTE Apportionment Tables.xls]WTE APP TABLES SUB F’!$B:$K,9,0))

and here’s method no 3 that feels somewhat neater:

=IF([WTE Apportionment Tables.xls]WTE APP TABLES SUB F’!$B:$K,L$7&$C13),VLOOKUP(L$7&$C13,’[WTE Apportionment Tables.xls]WTE APP TABLES SUB F’!$B:$K,9,0))

That’s a working formula but it is a bit confusing, so here’s a simpler example the syntax:

=IF(COUNTIF(A1:A10,”Some Value”),VLOOKUP(“Some Value”,A1:B10,2,FALSE),0)

The COUNTIF function is a logical function and will return TRUE or FALSE depending on whether “Some Value” is found in the range A1:A10. The IF function follows the format =IF(logical test, value if true, value if false). So if the COUNTIF function is TRUE the VLOOKUP will run, if it is FALSE the value 0 is returned.

Spreadsheet Efficiency: VLookup and Conditional Formatting to Remove Errors

I’ve started working at a new hospital and it seems to be plagued by unwieldy spreadsheets that have a tendency to crawl through saves and then sometimes refuse to open. They are riddled with links and lookups to external spreadsheets and the whole thing feels fairly precarious.

I’ve been reading a bit about good spreadsheet design with a view to whittling down the complexity and discovered that lookup functions are particularly demanding on the system.

Now I’m quite a sinner when it comes to the use of the double lookup function to remove errors such as #N/A and #DIV/0!

Here’s an example of such a formula that returns a blank if the first lookup function results in an error:

=IF(ISERROR(VLOOKUP(L$7&$C13,'[WTE Apportionment Tables.xls]WTE APP TABLES SUB F’!$B:$K,9,0)),””,VLOOKUP(L$7&$C13,'[WTE Apportionment Tables.xls]WTE APP TABLES SUB F’!$B:$K,9,0))

It works fine, but it doubles up the number of lookups that Excel needs to run through and for a large spreadsheet this can really slow down the performance.

It seems that conditional formatting is a suitable alternative but one that I’ve always ignored because I didn’t know how to structure the condition to work for errors.

I do now though and here’s how:

excel

1. Select the range you wish to apply the format to.
2. Goto Format – Conditional Formatting
3. Select Formula Is in the drop down box
4. Type the formula =iserror(ref) where ref is the reference to the first cell selected in the range
5. Hit Format and select the font colour to be white
6. OK – finished the job

Conditional Format 2

My current spreadsheet hasn’t grown that large yet but nevertheless it had 7200 of the double vlookups in 18 columns, by removing the unnecessary error catching lookup I dropped the file size by 22%.

As the errors weren’t actually removed, I had to use an array formula to get the totals for the column but that was included in the space saving above.

The array formula for summing a range with error values:

{=SUM(IF(ISNUMBER(H12:H418),(H12:H418)))}

NB. The curly brackets are achieved by entering the formula using CONTROL, SHIFT, ENTER.

Adding an Image to the Header or Footer of Every Sheet

From Excel 2002 onwards you can enter an image, probably a logo, into the header or footer of your worksheet. This code enables you to create a macro that will automate the addition of the logo to every sheet in your workbook.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Sub MultipleHeader()
'created 10/01/2008 by Angela Wolff
Application.ScreenUpdating = False 'stops the flashing
   Dim WS_Count As Integer
   Dim I As Integer

   ' Set WS_Count equal to the number of worksheets in the active workbook.
   WS_Count = ActiveWorkbook.Worksheets.Count
   
   ' Begin loop.
   For I = 1 To WS_Count
      ActiveWorkbook.Worksheets(I).Activate
      ActiveSheet.PageSetup.RightHeaderPicture.Filename = _
        "C:\Document\hhnt_007528.jpg"  'obviously change this to the image and path of your desire.
    ActiveSheet.PageSetup.PrintArea = ""
    With ActiveSheet.PageSetup
        .RightHeader = "&G"
    End With
   Next I
End Sub

NB. The With End With code is only really required if you are going to change a number of parameters at once.

Scroll Bar Chart

This is a very neat advanced Microsoft Excel technique that enables the spreadsheet user to alter the visible range displayed. This can be achieved by defining the start point within the spreadsheet data series and also the number of data points to display in the Excel spreadsheet chart.

All the examples are available to examine in the Microsoft Excel example spreadsheet: Scroll Bar Chart

scroll-pic-a.jpg

In this example I have a full years data displayed in the worksheet range $A1:$C53.

scroll-pic-b.jpg
We need to create the two slide bars on the Excel worksheet.

Open the forms toolbar within Excel and select the scroll bar option and then drag out the form of a horizontal bar. You can move this around to finalise both size and positioning.

Right click over the selected scroll bar and choose Format Control.
In the box called Cell link write $L$19. This is the cell in which the incremental value of the slide bar will be recorded.
Repeat the process by drawing another scroll bar and assign its cell link to $L$21.

If you now move the arrows either side of the two scroll bars you will see that the values in the corresponding cell link will change. These will form the values for the height of our displayed values and the starting point respectively, and as such they will appear in our offset function defining the y values. To make these offset formulas easier to read I suggest we name the cell links.

To add a name to a specific cell or area – from the Insert menu, choose Name and then Define or use the keyboard shortcut CTRL F3. In the “Names in workbook” box type in a descriptive name for your cell, in this case I have used ZoomValue.
In the “Refers to” box we simply type $L$19.

Similarly for ScrollValue the name is defined as:

scroll-pic-c.jpg

We need to set a dynamic range for the x and y values. So, taking the y values as our base we can use the offset function to define the values to be plotted.

The OFFSET function is in the following format:

ref,rows,cols,height,width.

Choosing $C$2 as our reference cell, we now require a measure of our starting point (given by our SCROLL slide bar), the cols section = 0, the height relates to the number of rows of data to be charted and is returned by our ZOOM slide bar and the width = 1.

So define the named range =

OFFSETSheet1!$C$2,ScrollValue,0,ZoomValue,1)

The x values or labels can simply be referenced from the y values:
scroll-pic-d.jpg

When you create the graph you need to the dynamic ranges for the x and y values, so in this example the formulas would be:

x axis values = Sheet1!XValues
y axis values = Sheet1!YValues

xval-chart.jpg

series-chart.jpg

This is your dynamic chart completed. Try the arrows on both scroll bars to see how they alter the display.

You can hide your data table so long as you remember to change the chart options so that hidden cells are plotted and the cell links can be formatted so they too are not visible.

See the Microsoft Excel spreadsheet example Scroll Bar Chart.

Dynamic Chart

This Microsoft Excel tutorial, shows an example of how to create a dynamic chart by moving the charting range as data is added to the spreadsheet.
Here we start with monthly data for Retailer A, showing Petcare sales complete up to July.

pic-a.jpg

A standard Excel line chart of this data would be shown thus:

pic-b.jpg

To reduce the displayed area to the existing data within the actual column, while allowing it to expand automatically as more months figures are added, we use defined names.

Insert menu, choose Name and then Define or use the keyboard shortcut CTRL F3.

In the “Names in workbook” box type in a descriptive name for your chart data, in this case I have used ChartActual.
In the “Refers to” box we use the offset function to define the data within column C.

pic-c.jpg

The offset function is written in the following format:

=OFFSET(Ref,rows,column,height,width)

The COUNTA function is the vital part that makes the range responsive to the number of cell entries in the Actual column. This function returns the number of non-blank cells in a range. It is written in the height section of the OFFSET function and therefore determines the number of rows that will make up the name ChartActual.

In this example the reference is $C$1 which corresponds to the “Actuals” title, the resulting area starts 1 row down and 0 columns across. The number of rows corresponds to the number of entries in column C less 1 for the title entry and the total column width is 1.

The same procedure is now used to define names for the ChartLabels and ChartTargets.

pic-d.jpg

The OFFSET function is again used, this time referencing the newly defined ChartActuals. So ChartTarget starts on the same row as ChartActuals but is 1 column to the left of it. When the height and width component of the OFFSET function is not stated the height and width will be the same as the reference.

pic-e.jpg

The final stage involves changing the graphs data source.
Right click within the graph and choose Source Data.

pic-f.jpg

Select Actual in the Series box and in the Values box type in the newly defined name, in this case Sheet1!ChartActuals.
Perform the same action for Target and use Sheet1!ChartLabels to define the Category (X) axis labels.
Click OK and the chart should now look like this but is in addition fully responsive to new entries.

pic-g.jpg

Sumproduct

All the worksheets (and some extras) shown in the microsoft excel tutorial below are included in the example spreadsheet, available to download Sumproduct.xls

This is quite a special excel spreadsheet function but the online help available from microsoft is unfortunately pretty poor.

It works as an advanced form of the SUMIF formula where you can sum a range of values based on a number of different criteria.

Here is the simple formula layout or syntax:

=SUMPRODUCT((Condition 1)*(The range to sum))

or slightly more complex:

=SUMPRODUCT((Condition 1)*(Condition 2)*(The range to sum)

the “*” symbol between conditions represents an AND a “+” symbol would represent an OR.

Here is a simple example, of a schools course grades displayed in the following spreadsheet table,
sumproduct

You will probably want to summarise this to show the total number of students passing the course in each grade.

sumproduct

This makes use of the simple SUMPRODUCT formula in cell F2:

=SUMPRODUCT(($B$2:$B$15=E2)*($C$2:$C$15))

the use of absolute referencing here enables the formula to be copied all the way down the table.

In English the spreadsheet formula reads:

Sum the results in column C where the values in column B = “A”

Moving on to a slightly more complex example, we could increase the summary table to show each students performance across the different grades.

sumproduct

This requires the addition of another condition – namely STUDENT equals.

The spreadsheet formula in cell I2, which can again be copied across is:

=SUMPRODUCT(($B$2:$B$15=I$1)*($A$2:$A$15=$H2)*($C$2:$C$15))

In English the spreadsheet formula reads:

Sum the results in column C where the grades = “A” and where the student = “Adam”

To see these powerful excel functions in action and utilising the Condition 1 OR condition 2 terminology, download my example microsoft excel spreadsheet.