Case:
I inserted a new columns name:(Date) and (Time) to column D and E.
But I can't define the last low in column D and E, because of there have no data under D and E.
What i want to do:
column C
1/8/2016 8:24:08
I want to get date 1/8/2016 to column D. and time 8:24:08 to column E.
I found some information about how to find the last row or last column.
http://www.thespreadsheetguru.com/blog/2014/7/7/5-different-ways-to-find-the-last-row-or-last-column-using-vba
But i still not understand how to let vba know the last row. Can please someone can help me know, how am i need to define it. Thank you.
LastColumn = ??
Range("D2:D" & LastColumn).Formula = "=LEFT(C2,(FIND("" "",C2,1)-1))"
My excel page
as to your specific issue
since you already have a "complete" date in column "C" cells, you just need to use TEXT() function to parse it down to the wanted part, as follows:
....FormulaR1C1 = "=TEXT(RC3,""gg/m/aaaa"")"
....FormulaR1C1 = "=TEXT(RC3,""hh:mm:ss"")"
where you'd also use .FormulaR1C1 property to adopt R1C1 style address notation which is more useful for the current purpose letting you write RC3 and refer to column "3" (i.e. column "C") cell in the same row of where you're writing the formula in
as for the lastRow issue
to get the last non empty cell in a given column you'd write something like:
lastRow = Cells(Rows.Count, "C").End(xlUp)).Row '<--| get column "C" last non empty cell row
but please note that should the given column be empty then it'd return 1 as if cell in row 1 were not empty. so you may want to add a check like the following:
lastRow = Cells(Rows.Count, "C").End(xlUp)).Row '<--| get column "C" last non empty cell row
If .Cells(GetLastRow, "C") = "" Then lastRow = 0 '<--| return 0 if empty column
and handle the case of a return "zero" value
furthermore note that the above code implicitly assumes currently active workbook and worksheet reference, which can often be not safe should you (or your code) make any worksheet/workbook "jumping".
so you'd better add explicit worksheet (and workbook) references like follows:
lastRow = Workbooks("MyWorkbookname").Worksheets("MyWorksheetName").Cells(Workbooks("MyWorkbookname").Worksheets("MyWorksheetName").Rows.Count, "C").End(xlUp)).Row '<--| get column "C" last non empty cell row
If Workbooks("MyWorkbookname").Worksheets("MyWorksheetName").Cells(GetLastRow, "C") = "" Then lastRow = 0 '<--| return 0 if empty column
where you HAVE to qualify those workbook/worksheet references in EVERY range reference
now, you can take advantage of the With keyword to both lessen the burden of typing all that jazz and make code more readable and maintainable, as follows:
With Workbooks("MyWorkbookname").Worksheets("MyWorksheetName")
lastRow = .Cells(.Rows.Count, colIndex).End(xlUp).row
If .Cells(lastRow, colIndex) = "" Then lastRow = 0
End With
so that you can finally type your following GetLastRow() function:
Function GetLastRow(sht As Worksheet, colIndex As Long) As Long
With sht '<--| refer to the passed worksheet
GetLastRow = .Cells(.Rows.Count, colIndex).End(xlUp).row '<--| get its passed column last non empty cell
If .Cells(GetLastRow, colIndex) = "" Then GetLastRow = 0 '<--| check for empty column
End With
End Function
getting it all together you may may come up to the following code
Sub main()
With Workbooks("MyWorkbookName").Worksheets("MyData") '<--| refer to your worksheet (change "MyData" to your actual sheet name)
With .Range("C1", .Cells(.Rows.Count, "C").End(xlUp)) '<--| refer to its column "C" range from row 1 down to last non empty cell
.Offset(, 1).FormulaR1C1 = "=TEXT(RC3,""gg/m/aaaa"")" '<-- write date in column "C"
.Offset(, 2).FormulaR1C1 = "=TEXT(RC3,""hh:mm:ss"")" ' <-- write hour in column "C"
With .Offset(, 1).Resize(, 2)
.value = .value
End With
End With
End With
End Sub
you may then want to change it and use the GetLastRow() function
Related
I want the VBA code to use the value from B1 and present the result in A1, then the VBA code uses the value from B2 and presents the result in A2.
It works for B1 as I get the value in A1. I visible see the cursor on the excel sheet move down the B column, but nothing changes in the A column for results, not even the A1 cell is being overwritten.
It seems that the changing of rows works. However, the code isn't updating to utilize other cells in column A to post results.
This code is pulling an email address from B1, using the LDAP VBA function to make an inquiry of an active directory, and then returning the DisplayName of the member of the email into cell A1.
Range("B1").Select
' Set Do loop to stop when an empty cell is reached.
Do Until IsEmpty(ActiveCell)
ActiveSheet.Range("A1").Value = gigIDldap(4, True, Range("B1")) <--A1 will have the value from the gigID1dap VBA function using the value listed in B1
' Insert your code here.
' Step down 1 row from present location.
ActiveCell.Offset(1, 0).Select
Loop
' ******This didn't work. It gave a type mismatch error
For Each Row In ActiveSheet.Rows
ActiveSheet.Range("A1").Value = Row.Value
For Each cell In Values
ValueCell = Range("B1")
Next cell
Next Row
End Sub
Something like this?
Dim r As Long 'row pointer
With ActiveSheet
For r = 1 To .Cells(.Rows.Count, "B").End(xlUp).Row 'loop from row 1 to last used cell in column B
.Cells(r, 1).Value = gigIDldap(4, True, .Cells(r, 2).Value) 'write to column 1 with result from column 2
Next
End With
After failing to figure out how to do that for a while, I'll try my luck here:
I'm essentially trying to compare two situations using VBA.
A similar (and a lot simpler) example:
F2, for example, calculate 152+D2, while F3 calculates 185+D3.
I wish to run a macro that would check the effect of one person getting a different amount of points. For example, if A2 = Max the macro should assign the value of A3 (18) to D3. If A2 = Lewis, 18 would become the new value of D2.
Tried using vlookup and match+index in order to find the cell that I want to change. When using vlookup, the code looked similar to this:
First I copied F2:F4 to I2:I4, so the results would be comparable. Then tried to replace the value of D2:D4 according to A2&A3:
name = Range("A2").value
newvalue = Range("A3").value
Find = Application.VLookup(name, Range("C2:D4"), 2, False)
Find.value = newvalue
Perhaps I should be looking for the cell itself, and not the value, and then it would work (maybe using offset, or offset+match? couldn't make it work)?
Would appreciate any help!
Not really sure what the intention is but this seems like a fun challenge.
So logic is this. We look for the name in column C. If we get a match we will get a row back as an answer, then we replace the value from "A3" and add it to the row we got but to the column D.
Maybe something like this :D?
Option Explicit
Sub something_test()
Dim lookup_val As String
Dim lrow As Long
Dim lookup_rng As Range
Dim match_row As Long
Dim ws As Worksheet
Set ws = Worksheets("Sheet1") 'Name the worksheet
lrow = ws.Cells(Rows.Count, "C").End(xlUp).Row 'Find last row in Sheet1
lookup_val = ws.Cells(2, "A").Value 'Set the lookup value
Set lookup_rng = ws.Range("C2:C" & lrow) 'set the lookup range
match_row = Application.Match(lookup_val, lookup_rng, 0) + 1 'Find the name in column C. Add +1 since the range starts at row 2. We will get the row number back
ws.Cells(match_row, "D").Value = ws.Cells(3, "A").Value 'Take the value from "A3" and replace the existing value at the row we found, but for column D
End Sub
The task at hand is to search in column A to see what values I have (they are in form of letters) and paste for each unique entry, its value once in another column.
Here is a visual explanation:
What I came up with was to create a For loop that iritiates through column A and created a conditional that if it found a certain value then it would insert the value in the range. Here is the code:
For i = 1 to 26
if cells(i,26).value= "A" Then
Range ("C1")= "A"
Elseif cells(i,26).value = "B" then
Range ("C2").value = "B"
ElseIf (i,26).value = "C" then
Range ("C3").value = "C"
EndIf
Next i
end sub
I want to cut this process short as my data set is really big with lots of company names. Any recommendations? I believe there has to be a way of knowing the values without having to look at all the values yourself.
If the goal is to just get a unique list of values found in Column A output to Column C you can use the below macro. This is really just recreating the steps of one method you would manually take to find unique values. Not the most sophisticated solution, but it works
Create a copy of your column with company names (using last available column in sheet)
De-dup the helper column
Copy the de-duped column to destination
Delete the helper column
Assumes the last column on worksheet is not used
Sub Unique()
Dim ws As Worksheet: Set ws = ThisWorkbook.Sheets("Sheet1")
Dim lr As Long, lc As Long
'Determine Range Size
lr = ws.Range("A" & ws.Rows.Count).End(xlUp).Row
lc = ws.Cells(1, ws.Columns.Count).Column
'Copy Company Names To Helper Column/Remove Duplicates
ws.Range("A2:A" & lr).Copy ws.Cells(1, lc)
ws.Columns(lc).RemoveDuplicates Columns:=1, Header:=xlNo
lr = ws.Cells(ws.Rows.Count, lc).End(xlUp).Row
'Output Unique Values From Helper Column
ws.Range(ws.Cells(1, lc), ws.Cells(lr, lc)).Copy
ws.Range("C2").PasteSpecial xlPasteValues
'Delete Helper Column
ws.Columns(lc).Delete
End Sub
Note my comment on post. VBA may not be needed here at all
Here's a slightly different version of using .RemoveDuplicates which also removes blank cells.
You can also do this without VBA. Just copy the desired column to another and use Remove Duplicates under Data tab.
Sub Unique_Values()
Dim ws As Worksheet: Set ws = ThisWorkbook.Sheets("Sheet1")
'Getting all the values in column A (except header)
'Copying them into cell C2 and below
ws.Range("A2", Range("A1048576").End(xlUp)).Copy Range("C2")
'setting the header for the column C
ws.Range("C1").Value = "What companies are in Column A?"
'Removing duplicates and blanks from column C
With ws.Range("$C$2", Range("C1048576").End(xlUp))
.Value = .Value
.RemoveDuplicates Columns:=1, Header:=xlNo
On Error Resume Next
.SpecialCells(xlCellTypeBlanks).Delete xlShiftUp
On Error GoTo 0
End With
End Sub
Although I agree with the coding convention used in the other answer, I think it is over-complicating the problem a little bit that would cause confusion for beginners.
I think both answers so far will give you exactly what you want, and perhaps could be simplified even further?
Sub GetUniqueQuick()
Dim LastRow As Long
Application.ScreenUpdating = False
LastRow = Sheets("Sheet1").Cells(Rows.Count, 1).End(xlUp).Row
Sheets("Sheet1").Range("A2:A" & LastRow).Copy Sheets("Sheet1").Range("C2")
Sheets("Sheet1").Range("C1:C" & LastRow).RemoveDuplicates Columns:=1, Header:=xlYes
End Sub
Using the dynamic features of MS 365 you can simply apply the worksheet function UNIQUE() over a given range, e.g.
= UNIQUE(A2:A100)
or integrate it in a user defined function
Function GetCompanies(rng As Range)
If rng.Columns.Count > 1 Then Exit Function ' allow only one column
GetCompanies = Application.Unique(rng) ' return function result as 2-dim array
End Function
As empty cells result in pseudo-uniques with a 0 output, you could call them in formula with an added cosmetical blank string :
=GetCompanies(A2:A100)&""
I am trying to extend a sum formula to a dynamic range. The sum includes all values from row 5 till the second last used row in the column, the sum is then in the last used row. However, the number of rows and columns vary, the only thing that stays the same is that the sum should always start in row 5. The sum starts also always in column C. I already managed to write a macro that puts the sum in the last row of column C. I am now working on a macro that extends this sum to all other used columns in the sheet, except for the last column (that contains another value and not a sum).
I am working with selection.autofill. However, I am having issues with declaring the range that i want to fill. VBA gives me an "expected: end of statement" error and I can't figure out why. Can somebody explain to me what I am doing wrong? Is there a better method than selection.autofill - i fear that it might not take over the columns, e.g. actually summing up column D when extended to the cell in column D ?
Here is what i already have:
'
' sumtest Macro
'
'
Dim Cell As Range, sRange As Range
Dim wsDestination As Worksheet
With ThisWorkbook
Set wsDestination = .Worksheets("Overview")
End With
FirstRow = Rows(5).EntireRow
lastRow = wsDestination.Cells(Rows.Count, "A").End(xlUp).Row
LastRow1 = wsDestination.Cells(Rows.Count, "A").End(xlUp).Row
LastColumn1 = wsDestination.Cells(4, wsDestination.Columns.Count).End(xlToLeft).Column
Worksheets("Overview").Select
wsDestination.Cells(lastRow, "C").Select
ActiveCell.Formula = "=SUM(C5:C" & lastRow - 1 & ")"
Range(wsDestination.Cells(LastRow1, 3)).Select
Selection.AutoFill Destination:=Range(wsDestination.Cells(LastRow1,3),wsDestination.Cells(LastRow1,LastColumn -1)) Type:=xlFillDefault
End Sub
This code would write the value of the sum in each column for the last row:
Option Explicit
Sub Sumtest()
With ThisWorkbook.Sheets("Overview")
Dim LastCol As Long: LastCol = .Cells(4, .Columns.Count).End(xlToLeft).Column
Dim Cell As Range
Dim LastRow As Long
For Each Cell In .Range("C4", .Cells(4, LastCol))
LastRow = .Cells(.Rows.Count, Cell.Column).End(xlUp).Row
.Cells(LastRow, Cell.Column) = Application.Sum(.Range(Cell.Offset(1), .Cells(LastRow - 1, Cell.Column)))
Next Cell
End With
End Sub
Note that the code will check the LastRow for every column, so if the columns have different amount of rows the total will be on the first row without data for each column.
Hello!
I am trying to build a macro, that finds a blank cell in a range in a single column and sums all cells between this blank cell and the previous blank cell.
I've searched the web a lot, and while others have asked this question, i do not find the answers to them particularly helpful in my situation, as i need this to work through 3500+ rows.
E.g:
4
3
4
BLANK 1
2
5
7
1
BLANK 2
1
4
BLANK 3
In this case the cell called "BLANK 1" would be the sum of the 3 previous rows: 4+3+4=11
"Blank 2" would be 15 and so forth.
The range is "G8:G3561".
Edit
For the quick answer see Mr_Nitrogen's answer. It works beautifully!
However, as I am new to VBA and coding in general I do not know how or why the code works.
I am very eager to obtain a better understanding of VBA, which is why I'm continuing this thread (if allowed to).
Furthermore, I would like to provide evidence for the commenters that I have indeed worked on this myself and that I prefer to build my own code.
It's important for me to understand why my code works or doesn't work, which is why i hope that you still want to help me develop my own code.
I finally found an approach that is logical to me. I know that this is not the simplest way to do it, but I would like to know if it could work.
I've written the following code.
Sub Sum_storage()
Dim rng As Range
Dim cell As Range
Dim cell2 As Range
Dim cell3 As Range
Range("G8").End(xlDown).Offset(1, 0).Select
Set cell = Selection
cell.Value = "temp" 'Finds the first blank cell in column G _
and creates a temporary value in order _
to find the second blank cell
Range("G8").End(xlDown).Offset(1, 0).Select
Set cell2 = Selection
cell.Offset(1, 0).Select
Set cell3 = Selection 'The range i need to sum can _
now be described as "cell3:cell2"
Set rng = Range(Range("cell3"), Range("cell2")) 'The code works until this point
cell2.Value = WorksheetFunction.Sum(rng)
The idea is to define the range i want to sum with multiple variables.
My problem is trying to refer to these variables (and setting them in an easier way than using .Offset).
Is it simply not possible to set a range (rng) based on two previously set ranges?
If this is possible the next step for me is creating some kind of loop that could make this work for all 3500+ rows.
You were on the right track with using End(xlDown).
This one should be a way faster than looping through all cells, because this jumps to the next empty cell and sums via WorksheetFunction.Sum.
Option Explicit
Public Sub DoMyStuff()
Dim ws As Worksheet
Set ws = Worksheets("Tabelle8") 'define your worksheet here
Dim FirstCell As Range
Set FirstCell = ws.Range("G8")
Dim VeryLastCell As Range 'get very last cell as stop criteria
Set VeryLastCell = ws.Cells(ws.Rows.Count, "G").End(xlUp)
Do
Dim LastCell As Range
If FirstCell.Offset(1) = vbNullString Then 'test if there is only one cell to sum
Set LastCell = FirstCell
Else
Set LastCell = FirstCell.End(xlDown)
End If
With LastCell.Offset(1, 0) 'this is the cell we want to write the sum
.Value = Application.WorksheetFunction.Sum(ws.Range(FirstCell, LastCell))
.Interior.Color = RGB(255, 0, 0)
End With
Set FirstCell = LastCell.Offset(2, 0)
Loop While FirstCell.Row < VeryLastCell.Row
End Sub
This isnt that complicated to do with for loop, maybe something like
lastrow = Cells(Rows.Count, "G").End(xlUp).Row
firstrow = 8
TempTotal = 0
for x = firstrow to lastrow + 1
If Cells(x, "G") <> "" Then
TempTotal = TempTotal + Cells(x, "G")
Else: Cells(x, "G") = TempTotal
Cells(x, "G").Interior.ColorIndex = 4
TempTotal = 0
End if
Next x
Ive made an edit to make it a bit simpler
The Logic of the Code:
Define the last row with data in column "G"
Move down cell by cell until that row
If the cell has a value in it, add it to the temporary total.
If it is blank, inset the temporary total and reset the tempTotal to zero
This is the first line, in which we select the very last last cell in column "G", use use End(xlup) on it to get to the last cell with data and use .row to get the row number of that cell
Set up a For loop, which runs the code between "for" and "next x" lines repeatedly while incrementing the value of x from "firstrow" to "lastrow + 1" each time it repeats ( so if firsrow is 1 and lastrow is 100) then it will run the code 100 times with x = 1,2,3,4,5 etc.)
this is the "if" statement, "<>" means does not equal, so we are saying if the cell on row x, col "G" is not equal to "" which is an empty string (or nothing) then we do the next line (add its value to tempTotal)
if the "If" statement isnt true (if the cell is blank) then we do what is under the "Else" and make that cell equal to TempTotal, change its color to green (4 is a colorcode, they go between 1 and 50), and reset the temptotal to 0.