Yesterday I learned here how to copy a row to a second sheet.
Sub maJolieProcedure(Texte As String)
With Worksheets("employes").Range("A:A")
Set c = .Find(what:=Texte)
If Not c Is Nothing Then
firstAddress = c.Row
Worksheets("employes").Rows(firstAddress).Copy _
Destination:=Worksheets("rapport").Range("A1")
MsgBox "Ok"
Else
MsgBox "Nok"
End If
End With
End Sub
To respect the formatting of the second sheet, I want to copy and paste the contents of each cell one by one.
I can identify the line number. However, I can't figure out how the Range object can return each cell one by one. For example, C3 content if Rows = 3.
Thanks a lot.
If you don't want to paste the formatting from one range to another paste values only.
Worksheets("employes").Rows(firstAddress).Copy
Worksheets("rapport").Range("A1").PasteSpecial xlValues
That's the same for all ranges, whether 1 cell or a million. The Copy process copies the subject to memory as one block. Any parsing must be done before the Copy instruction. An alternative is to read a range into an array.
Dim Arr As Variant
Arr = Worksheets("employes").Rows(firstAddress).Value
This will create a 3D array of 1 row and about 16000 columns. You might decide to limit your enthusiasm to only what you need.
With Worksheets("employees")
Arr = .Range(.Cells(firstAddress, 1), .Cells(firstAddress, .Columns.Count).End)xlToLeft)).Value
End With
Pay attention to the leading periods within the With statement. Each such period stands for the object mentioned in the With statement.
If your goal is to respect the formating of the second sheet, you don't need to loose time copying cell by cell.
It is more effective to do a paste special, like you do with the mouse:
Range("A1").Copy
Range("B1").PasteSpecial Paste:=xlPasteValues
works very well also with bigger ranges if you need:
Range("A1:A12").Copy
Range("B1:B12").PasteSpecial Paste:=xlPasteValues
or even
Range("A1:A12").Copy
Range("D3").PasteSpecial Paste:=xlPasteValues
If your goal is to really access all cell of a range individually , you just iterate on the range. For example:
For Each cell In Range("A1:A12")
cell.Value = cell.Value + 2
Next cell
Related
I'm using VBA code to write to cells in excel. For eg.
Range("C3") = code
Or
Cells(3,3) = code
If a row is inserted in the sheet, the code does then not update accordingly and would still write to Range("C3") etc. So the code then writes to the incorrect cell.
Is there a better way I can structure my code so it will update accordingly? Perhaps using a table instead of cells?
One solution is to used Named Ranges. You can define a Named Range in Formula Tab by clicking on Name Manager.
Then you will write.
Range("Name of the Range") = code
My believe is that named ranges update automatically when a row or column is inserted, so your code will print the value in the correct cell.
Thanks, good idea. I ended up defining the column filled with values as a range, then use a for loop to search for the defined string. That way it doesnt matter what row it is in aslong as the name and string doesnt change (Using a Named Range will probably be better for that exact reason).
Worksheets("Sheet1").Select
Set WS = ActiveSheet
With WS
LastRow = .Cells(.Rows.Count, 2).End(xlUp).Row 'Determine the last row number with data in it for column B
For Each acell In .Range("B1:B" & LastRow) 'Defines the search range from B1 to last row
If acell.Value = "String Searched For" Then
'Do stuff based on found cell location
End If
If acell.Value = "String Searched For#2" Then
'Do stuff based on found cell location#2
End If
Next
End With
I'm trying to loop through a data set in Excel where the deciding factors for each block of rows is based on the second column (WO#) because I want to perform calculations (not part of this question) just for items in the same grouping.
Visualization on iterating through blocks of rows
Sub test()
Dim totalHrs As Integer, lastRow As Integer
Dim block As Range, dataSet As Range
lastRow = ActiveSheet.Cells.SpecialCells(xlCellTypeLastCell).Row
Set dataSet = Range("A2:G" & lastRow)
For Each block In Columns("B").SpecialCells(xlCellTypeConstants, xlTextValues).Areas
'Do calculation stuff
Next block
End Sub
Right now I am having trouble defining what range 'block' should be since it will constantly change. A block begins when the "WO#" column is one number, and the block ends once that column's value changes to something else. How do I go about defining this range?
An easier way would be to just extract rows that have the same WO# into a new table and do the calculations there, but since this dataset can get quite large I would prefer not to do that as the macro will become way too heavy
What if you added this into G11 =IF(B11=B12,F12,C11) and then in F11 you added =G11-E11 and then dragged them down.
It should check to see if it's the last entry in the set and then set itself to the delivery date or set itself equal to the start day of the line below.
Edit:
Try replacing the F11 cell with this =WORKDAY(G11,-E11) and dragging down to account for workdays. To account for holidays, you can create a second sheet to list them out as dates and then add them as a range for the third, optional, argument in the Workday function. Please see the Workday documentation if more clarification is required on the function's use.
The code below defines blocks of similar values in a column. To use this code, either add a column to your worksheet combining columns B and C into one value (=B11&C11) or edit the code to check two columns (If rngCell.Offset(0, 0).Value = rngCell.Offset(1, 0).Value And rngCell.Offset(0, 1).Value = rngCell.Offset(1, 1).Value Then). Also, expand the blocks to more than one column.
'Starts the first block with the first cell in a column.
Set rngBlock = rngColumn.Cells(1)
'Checks every cell in a column.
For Each rngCell In rngColumn
'Checks whether a cell's value equals the cell below it.
If rngCell.Value = rngCell.Offset(1, 0).Value Then
Set rngBlock = Union(rngBlock, rngCell.Offset(1, 0))
'If equal, includes the cell below in the block.
Else
'If not equal, does something with the block...
Debug.Print rngBlock.Address
'Starts the next block with the cell below.
Set rngBlock = rngCell.Offset(1, 0)
End If
Next rngCell
I'm new here and I apologize in advance in my question isn't clear... I couldn't find the answer after some research...
I'm looking for a way to go through all the cells of column "R" and if one cell on a given row contains "Y", then the values of cells at columns "W","X" and "Y" will take the same value as the columns "F","G" and "H" (always at the same row).
The goal is to have a button that will execute the VBA code in order to do this (instead of having to copy/paste all the time).
Thank you very much in advance for your help.
A poor ignorant but motivated VBA beginner...
Here is VBA which will do what you want. It takes advantage of the replacement operation being cells that are next to each other by using Resize.
Highlights
Iterates through each cell in column R. I used Intersect with the UsedRange on the sheet so that it only goes through cells that have values in them (instead of all the way to the end).
Checks for "Y" using InStr.
Replaces the contents of columns WXY with values from columns FGH. Since they are contiguous, I did it all in one step with Resize.
Code:
Sub ReplaceValuesBasedOnColumn()
Dim rng_search As Range
Dim rng_cell As Range
'start on column R, assume correct sheet is open
Set rng_search = Range("R:R")
For Each rng_cell In Intersect(rng_search, rng_search.Parent.UsedRange)
'search for a Y, case sensitive
If InStr(rng_cell, "Y") > 0 Then
'update the columns as desired
'takes advantage of cells being next to each other
Range("W" & rng_cell.Row).Resize(1, 3).Value = Range("F" & rng_cell.Row).Resize(1, 3).Value
End If
Next rng_cell
End Sub
I tested it on my end, and it works, producing the following after running:
I have a three-step process that should end up giving me Boolean values of True/False and also an occasional #N/A or #VALUE (which I actually want to keep as errors). I am using a workbook with multiple named worksheets and am pulling cell values from one tab through a VLookup, replacing a string in those values, and then making those values into a formula to be evaluated. Here's what I have so far; I've included comments in the code explaining where I'm stuck.
Public Sub DetermineRowsToExamine()
'Define what our Rows are for the calculations
Dim NumRecords As Long
NumRecords = Workbooks("POVA Daily Reporter.xlsm").Worksheets("Paste Daily Data").Range("B" & Rows.Count).End(xlUp).Row
Dim CellsForFormula As Range
Set CellsForFormula = Workbooks("POVA Daily Reporter.xlsm").Worksheets("Paste Daily Data").Range("g2", "G" & NumRecords)
'Now I Insert the VLookup
Dim WSLogic As Worksheet
Dim WSData As Worksheet
Set WSData = Workbooks("POVA Daily Reporter.xlsm").Worksheets("Paste Daily Data")
Set WSLogic = Workbooks("POVA Daily Reporter.xlsm").Worksheets("Logic Statements")
CellsForFormula.Value = Application.WorksheetFunction.VLookup(WSData.Range("B2"), WSLogic.Range("A:D"), 4, False)
'This works in principle, but the problem is the "B2" in the VLookup - I need the "B2" to change to "B3" related
'to each row, just as it would if I pasted the rows down the columns as an cell formula
'Now I want to take that value and perform a replacement:
CellsForFormula.Value = Application.WorksheetFunction.Substitute(Range("g2"), "ZZZ", "C2")
'Again, this works great, but I need it to replace "G2" or "G3" or whatever cell it's in.
'Finally, I then want to evaluate that cell as if it were a formula. When the above calculations are working,
'I end up with: AND(LEN(C2)=10,OR(LEFT(C2,2)="57",LEFT(C2,2)="13"))
'I want to evaluate this as a formula, basically making it =AND(LEN(C2)=10,OR(LEFT(C2,2)="57",LEFT(C2,2)="13"))
End Sub
I think what I'm just not understanding is how to get the Cell references in the VLookup and Substitute functions to relate to whatever row I'm in.
Agreeing with what #AlanWaage is saying, you should put the actual VLOOKUP formula in the cell. Then, to get the formula to update relative to its location, you can utilize copy and paste. Finally, once you have the formulas there, you can copy and paste values, and do your replacement based on the values now in CellsForFormula range. See the updated code below:
' Put the formula in the first cell of your range
CellsForFormula(1, 1).Formula = _
"=VLOOKUP(Paste Daily Data!B2,Logic Statements!$A$1:$D$10000,4,0)"
' Copy the formula to the rest of your range
CellsForFormula(1, 1).Copy _
Destination:=Range(CellsForFormula(2, 1), CellsForFormula(NumRecords - 1, 1))
' Copy and paste values to just get the values in your range
CellsForFormula.Copy
CellsForFormula.PasteSpecial Paste:=xlPasteValues
' Execute your replacement
for each cell in CellsForFormula
cell.Replace("ZZZ", cell.offset(0,-4).Address)
'Use the line below instead of the line above if you only
'want to replace if the entire value is "ZZZ"
'cell.Replace("ZZZ", cell.offset(0,-4).Address,xlWhole)
cell.Formula = "=" & cell.value
Next cell
---EDIT---
Note that I did Logic Statements!$A$1:$D$10000 instead of Logic Statements!A:D; this will be much faster than having Excel examine all rows in the columns A:D. Make this number larger or smaller as you see fit, but you should try to avoid using complete column/row references in formulas unless necessary
I'm trying to create a simple macro that copys the two first numbers in each cell in a column and printing them in a different column. This is in a excel-document with more than 1 worksheet. I've tried for a while to write the code, but with no prior experience, I have a hard time figuring out what to do. I know the "left()"-function is able to do this, but I don't know how I define which column to draw data from and to which column it will be printed. Any help will be greatly appreciated.
With no prior experience to writing VBA code, I am going to reccommend you stick to the formula method of doing. Honestly, even if you were familiar with VBA, you might still opt to use the formula.
A formula is put into the actual cell you want the value to be copied.
=LEFT(sourceCell, #of characters you want)
This is how it would look:
=LEFT(Sheet1!A1, 2)
Think of it as saying "this cell shall equal the first n characters in cell OO, starting from the left".
Once you are done with your formula, if you don't need it to be binded to the source anymore (if the sourceCell changes, so does the cell with the LEFT formula), you can highlight the cells, Ctrl + C to copy, then right-click and select Paste Special. Then select VALUE and hit OK and now the cells are hard-coded with the value they were showing, as if you typed it yourself.
Once you master using formulas, the next step is VBA. Don't go confusing yourself by jumping into VBA and writing code for ranges, etc. if you aren't comfortable with using =LEFT yet. One step at a time, and you'll be a pro before you know it. :)
Here is a quick sample sub to get you started:
Public Sub LeftSub()
Dim SourceRange As Range, DestinationRange As Range, i As Integer
'Define our source range as A1:A10 of Sheet1
Set SourceRange = Sheet1.Range("A1:A10")
'Define our target range where we will print.
'Note that this is expected to be of same shape as source
Set DestinationRange = Sheet1.Range("B1:B10")
'Iterate through each source cell and print left 2 bits in target cell
For i = 1 To SourceRange.Count
DestinationRange(i, 1).Value = Left(SourceRange(i, 1).Value, 2)
Next i
End Sub
How about
Sub foo()
Dim cell As Range
Dim sourceRange As Range
'//define the source column - looks for contiguous downward data from A1;
Set sourceRange = Range(Sheets("Sheet1").Range("A1"), Selection.End(xlDown))
'//iterate each cell
For Each cell In sourceRange
If IsEmpty(cell.Value) Then Exit For
'//example to place the value in corresponding row of column B in sheet 2
Sheets("Sheet2").Range("B" & cell.Row).Value = Left$(cell.Value,2)
Next
End Sub
Or an equivalent formula (in the destination cell)
=LEFT(Sheet1!A1,2)