I have a spreadsheet that looks something like this:
A B C D E F
1 Program Year Cycle Date Panel Mtg Rep
2 AAA 2019 1 5/21 ABA Tom
3 AAA 2019 1 5/23 ABB Erin
4
5 BBB 2019 2 6/4 BAB Jim
6
7 CCC 2019 3 7/16 CAB Tom
8 CCC 2019 4 8/27 CBB Kate
9
10
What I'm trying to have it do is, every time a row is skipped, that blank row will automatically be populated with the column headings. So in the example table above, rows 4 and 6 would contain the column headings, while row 9 would remain blank until information was entered on row 10. I've done every possible search I can think of, and haven't found anything that seems applicable. I'm not very familiar with VBA, so I came up with the following series of formulas:
A3) =IF(AND($A2<>"",$A4<>"",$A2<>$A$1),$A$1,"")
B3) =IF(A3=A$1,B$1,"")
C3) =IF(B3=B$1,C$1,"")
D3) =IF(C3=C$1,D$1,"")
E3) =IF(D3=D$1,E$1,"")
F3) =IF(E3=E$1,F$1,"")
These formulas are then extended to the rest of the sheet. This does what I want it to do, but it also fills 8,000+ cells with formulas, including circular references. Which, aside from having to deal with being alerted to the circular references, they also affect other aspects of my sheet, such as conditional formatting, identifying duplicate entries, etc.
As I stated, I'm not really very familiar with VBA, so I don't even know if this is doable using VBA. But if there is some way to achieve the same result without formulas, or at least without circular references, that is what I'm looking for. Thanks so much for any assistance.
This code should work:
see before:
and after:
Sub addHeaders()
Dim ws As Worksheet
Set ws = Sheets("Sheet3")
Dim lastRow As Integer
lastRow = ws.Cells(ws.Rows.Count, 1).End(xlUp).Row
Dim header As Range
Set header = ws.Range("A1:F1")
For rowNum = 2 To lastRow
If ws.Cells(rowNum, 1) = "" Then
If ws.Cells(rowNum + 1, 1) <> "" Then
ws.Range("A" & rowNum & ":F" & rowNum) = header.Value
End If
End If
Next rowNum
End Sub
Since you said you are new to vba here is quick quick intro to how to run a program:
Something like this is what you're looking for:
Sub tgr()
Dim ws As Worksheet
Dim rHeaders As Range
Dim rDest As Range
Dim ACell As Range
Set ws = ActiveWorkbook.ActiveSheet
Set rHeaders = ws.Range("A1:F1")
For Each ACell In ws.Range("A1", ws.Cells(ws.Rows.Count, "A").End(xlUp)).Cells
If Len(Trim(ACell.Value)) = 0 Then
If Not rDest Is Nothing Then
Set rDest = Union(rDest, ACell)
Else
Set rDest = ACell
End If
End If
Next ACell
If Not rDest Is Nothing Then rHeaders.Copy rDest
End Sub
Related
I would like to thank everyone for their feedback so far it has helped a great deal. one question that I am grappling with is how to make my column values even so I can do a dynamic subtototal.
Column k Column R Column Y Column AF Column AM Column AT
1 2 4 2 3 5
3 9 7 8 2 4
2 3 6 3 5 8
3 3 2
5
TOT 9 14 25 13 12 17
Column k Column R Column Y Column AF Column AM Column AT
1 2 4 2 3 5
3 9 7 8 2 4
2 3 6 3 5 8
3 3 2
5
TOT 9 14 25 13 12 17
on a monthly basis the column values can fluctuate, the question is how do I use VBA to create a dynamic sum based on the column with the most values.
Dim Rin As Range
Dim Rout As Range
Dim lRa As Long
lRa = Range("i" & Rows.count).End(xlUp).Row
Set Rin = ws.Range("i" & lRa)
Set Rout = ws.Range("I" & lRa)
aCell.Range("I11:P12", "R12:AY12").Copy
Rout.Offset(2, 0).Resize(1, 28).Formula = "=SUBTOTAL(9," &
Rin.Address(0, 0) & ")"
lR = ws.Range("I" & Rows.count).End(xlUp).Row - 1 ' Finds the last blank
row
ws.Range("I" & lR).PasteSpecial xlPasteFormats
If you know where your data starts you can use a method such as that given by Shai Rado.
You can't have any entirely empty rows or columns in the range.
You can then feed this lastRow variable into the range address for adding your subtotal formula.
Example: If your data is a continuous set of populated columns starting at Cell D3 the following will get the last used row number in the range of columns:
Option Explicit
Public Sub AddSubTotal()
Dim lastRow As Long
Dim lastCol As Long
Dim firstRow As Long
Dim rowHeight As Long
Dim wb As Workbook
Dim ws As Worksheet
Set wb = ThisWorkbook
Set ws = wb.Worksheets("Sheet2") 'change as appropriate
With ws.Range("D3").CurrentRegion 'change as appropriate
firstRow = .Rows(1).Row
lastRow = .Rows(.Rows.Count).Row
lastCol = .Columns(.Columns.Count).Column
rowHeight = lastRow - firstRow + 1
End With
With ws
.Range(.Cells(lastRow + 1, "D"), .Cells(lastRow + 1, lastCol)).FormulaR1C1 = "=SUBTOTAL(9,R[-" & rowHeight & "]C:R[-1]C)"
End With
End Sub
If you need a different method to find the last used row and last used column there a lots of available resources online including my favourite by Ron De Bruin Find last row, column or last cell. The appropriateness of each method is determined by the shape and properties of your range e.g. no blank columns or rows in range. So choose a method that is right for your data or that can test for different likely cases and apply different methodologies as appropriate.
It is quite difficult to give a definitive answer (and i don't want to code lots of different possible scenarios) to this question without knowing more about the nature and variability of the data. If you familiarise yourself with the methods of finding last row and column you will be able to implement those that suit your needs.
I've been looking around everywhere. But I don't know what words to google.
I want to remove every row where the cell in the C column doesn't contain 7 or 8 numbers. The problem is that I don't know how to code this.
What is the symbol in VBA code for 1 letter, 1 number, 1 or more letters, 1 or more numbers, space etc? I have been googling for hours but I guess I just don't know the right search words. Where or how can I find this? It's pretty dumb I know.
Thanks a lot.
EDIT:
#eirikdaude Thank you for your answer.
Somehow it doesn't work. This is what I have:
Dim lastRow As Long
lastRow = Cells(Rows.Count, 3).End(xlUp).Row
Dim i As Integer
For i = 2 To lastRow
If (IsNumeric(Cells(i, 3).Value) And Len(Cells(i, 3).Value) >= 7 And Len(Cells(i, 3).Value) <= 8) Then
' do nothing
Else
Rows(i).Select
Selection.Delete Shift:=xlUp
End If
Next i
I've been trying everything, but I don't understand why this code above doesn't work.
Does it matter that all my cells are formatted "standard" in excel? Because all data is imported from a txt file.
Unless you insist on using a regex for this, I'd simply check for the length of the value in the cell and if it IsNumeric.
In your case, something like this:
For Each c In rangeToCheck
If IsNumeric(c) And Len(c) >= 7 And Len(c) <=8) Then
do your stuff
End If
Next c
There two probably reason for which you code is no deleting the expected rows:
Expected lines to be deleted may be skipped by the code as it's deleting rows from top to bottom. When deleting several rows the correct method is to do it upwards (i.e. from bottom to top)
As your data is imported from a text file it's possible that values in column C have some extra blank spaces at the end. The use of TRIM takes care of this situation.
The code below includes both corrections:
Sub Rng_Delete_Rows()
Dim LRowLst As Long, LRow As Long
Dim vCllVal As Variant
'Change SheetName as required
With ThisWorkbook.Sheets(1) 'Use this if procedure resides in Data workbook
'With ThisWorkbook.Sheets(1) 'Use this if procedure does not reside in Data workbook
Application.Goto .Cells(1), 1
LRowLst = .Cells(.Rows.Count, 3).End(xlUp).Row
For LRow = LRowLst To 2 Step -1
Rem Get Cell Value At Once
vCllVal = Trim(.Cells(LRow, 3).Value2)
If Not ((IsNumeric(vCllVal) _
And Len(vCllVal) >= 7 And Len(vCllVal) <= 8)) Then
Rem Delete Row
.Rows(LRow).EntireRow.Delete
End If: Next: End With
End Sub
I'm trying to use vba to automate a simple process by getting a data from another sheet in the same workbook. I'm cannot just copy because the data is updated dynamically, if there is changes to the other sheet, it will be affected.
ActiveCell.FormulaR1C1 = "='Sheet2'!R[7]C[4]"
This is my first time doing vba and I think the R[7]C[4] meant sort of the coordinates of getting the value either vertically or horizontally based on the positivity and negativity of the numbers.
Sheet1
2-Jul
-------
item1 item2 3
item1.1 item2.2 43
total 46
3-Jul
-------
item1 item2 3
item1.1 item2.2 41
total 44
Sheet2
1-Jul
2-Jul 46 (works here)
3-Jul 44 (does not work here)
It will run through the dates on sheet 2 and show the total accordingly on the 2nd column. This is what I did.
For Each cell In Range("A1:A3")
If cell.Value = selDate Then
Range("B" & cell.row).Select
ActiveCell.FormulaR1C1 = "='Sheet1'!R[3]C[3]"
End If
Next cell
I place my selected cell on 2-Jul and it got the cell correct and took 46 but as for the second one that I ran by placing my selected cell on 3-Jul, it took data just one cell down from 46 than actually getting 44.
I'm going to go out on a limb as I suspect that your use of offset R1C1 formulas was due to some problems coming up with an adequate formula for retrieving the 'Total' from Sheet1 for each date on Sheet2.
Sub get_dated_total()
Dim rw As Long, ws1 As Worksheet, sFormulaR1C1 As String
sFormulaR1C1 = "=IFERROR(INDEX(INDEX(Sheet1!C3,MATCH(RC1,Sheet1!C1,0)):INDEX(Sheet1!C3,ROWS(C3)),MATCH(""total"",INDEX(Sheet1!C,MATCH(RC1,Sheet1!C1,0)):INDEX(Sheet1!C,ROWS(C)), 0)), """")"
Set ws1 = Worksheets("Sheet1")
With Worksheets("Sheet2")
For rw = 1 To .Cells(Rows.Count, 1).End(xlUp).Row
If IsDate(.Cells(rw, 1)) Then
If CBool(Application.CountIf(ws1.Columns(1), .Cells(rw, 1).Value)) Then
.Cells(rw, 2).FormulaR1C1 = sFormulaR1C1
End If
End If
Next rw
End With
Set ws1 = Nothing
End Sub
Well, might not be the best solution but I guess the latter ActiveCell.row refers to Sheet2 if I'm on Sheet2 Selection. Now I have to store a temp row number instead at the start to get the true ActiveCell.row which is the row of 2-Jul
Dim tmpRow As Integer
tmpRow = ActiveCell.Row
Then I'm gonna call it later
ActiveCell.Formula = "='Sheet1'!C" & tmpRow + 3
I Know how to build a loop macro to read all of the rows in a certain column, but what I do not know how to do is write it in such a way that it will select the data not in common and that may not sound correct so here is an excample:
column A
1
1
1
1
2
2
2
2
3
3
3
What I want is for the loop to look at column A but only the first row of the new data so it would look like this
Column A
1
2
3
Thank you,
Give this a try:
Sub Macro1()
Dim A As Range
Set A = Range(Range("A1"), Range("A" & Cells(Rows.Count, "A").End(xlUp).Row))
A.RemoveDuplicates Columns:=1, Header:=xlNo
End Sub
EDIT#1:
This will first copy to another sheet and then remove duplicates in the copy:
Sub Macro1()
Dim A As Range, B As Range
Set A = Range(Range("A1"), Range("A" & Cells(Rows.Count, "A").End(xlUp).Row))
Set B = Sheets("Sheet2").Range("A1:A" & A.Rows.Count)
A.Copy B
B.RemoveDuplicates Columns:=1, Header:=xlNo
End Sub
I need a formula or function which is going to fulfill my below mentioned need. I have a excel data of around 11000 rows and data looks somewhat like in Column A:
Now in column B i want the result to be printed like it mentioned below: which literally means it should count the values present in column A and print it in the column B, I don't need to repeat count:
Column A Column B
PC-101 1
PC-101 1
PC-102 2
PC-102 2
PC-103 3
PC-104 4
PC-106 5
PC-107 6
PC-104 4
PC-106 5
PC-106 5
I tried with the "count" series formulas but the result was null.
Even i wrote the macro as given below( which i got from stackoverflow) but even it is printing the repeating count:
Sub CountOccurence()
' Reference: Microsoft Scripting Runtime
Application.ScreenUpdating = False
Set oDict = New Dictionary
Dim wS As Worksheet
Dim r As Integer, rLast As Integer
Set wS = Sheet1
rLast = wS.Cells(1, 1).CurrentRegion.Rows.Count
For r = 3 To rLast Step 1
If Not (oDict.Exists(wS.Cells(r, 1).Value)) Then
oDict.Add wS.Cells(r, 1).Value, 1
Else
oDict.Item(wS.Cells(r, 1).Value) = oDict.Item(wS.Cells(r, 1).Value) + 1
End If
wS.Cells(r, 2).Value = oDict.Item(wS.Cells(r, 1).Value)
Next r
Set oDict = Nothing
Application.ScreenUpdating = True
End Sub
Can anyone help me regarding this? Thanks in advance.
I tried with the "count" series formulas but the result was null.
A simple Excel formula can do this.
Put 1 in Cell B1 and then put this formula in cell B2 and pull it down.
=IF(COUNTIF($A$1:$A2,A2)>1,VLOOKUP(A2,A:B,2,0),B1+1)
Assuming that your data in column a is sorted, you can simply place 1 in B2 this formula in B3 and copy it down:
=IF(A2<>A3,B2+1,B2)
:-)