I've written a macro that structures a lot of data and saving me for manual punching of numbers etc. The macro is written in stages were each part have been tested isolated and then integrated in loops or to the main code it self - this way each piece of code is tested so it functions accordingly to my intentions.
The goal for this part of code is to cycle through each row in the sheet, if the value of column 9, row I is different from the column 9, row I-1, then it will insert a new row (sum row). This action will be preformed in each worksheet, hence nested loop. When I wrote this macro isolated, without nesting loops, it functioned well.
Edit: To clearify, the code insert a row if and only if Cells(I, PrGr) = Cells(I - 1, PrGr) are unequal. Therefore I ask if they are the same, if they are so, do nothing - else, insert a row (i.e. Cells(I, PrGr) = Cells(I - 1, PrGr) are not equal.)
Running it in a nested loop causes a Run Time Error 13, type mismatch on the line with "If Cells(I, PrGr) = Cells(I - 1, PrGr) Then". In debugger, when I force it to continue, it does what it is supposed to do - creating the sum rows for in every sheet. This happens regardless of which sheet I set as the starting sheet.
I've tried to change the logic of the loop by testing with For Each ws In This.. and with the logic I have now For J = 1 to WS_ant. Both causes the error. I also searched around for clues, but non has come up with any solution appropriate for this problem.
Does someone have a clue to what is happening here, and how to fix it?
The code:
Sub OI_SJ()
'Selects the first sheet
Sheets(1).Activate
'Loop through sheets
Dim J As Integer
Dim WS_ant As Integer
Dim starting_ws As Worksheet
Set starting_ws = ActiveSheet 'remember which worksheet is active in the beginning
WS_ant = ThisWorkbook.Worksheets.Count
For J = 1 To WS_ant
ThisWorkbook.Worksheets(J).Activate
'If sheet = GRL, then terminate
If ThisWorkbook.Worksheets(J).Name = "LL - Sv" Or ThisWorkbook.Worksheets(J).Name = "RM - Sv" Then
'do something later
ElseIf ThisWorkbook.Worksheets(J).Name = "GRL" Then GoTo Term5
Else
Dim I As Integer
Dim PrGr As Long
PrGr = 9
Set aktivtark = ThisWorkbook.Worksheets(J)
With aktivtark
sistekolonne = aktivtark.Cells(1, .Columns.Count).End(xlToLeft).Column
sisterad = aktivtark.Cells(.Rows.Count, "A").End(xlUp).Row
End With
Application.CutCopyMode = False
Application.ScreenUpdating = False
With aktivtark.Range("A6", Cells(sisterad, sistekolonne))
.RowHeight = 15
End With
Rows(1).RowHeight = 24
For I = 6 To sisterad + 153
If Cells(I, PrGr) = Cells(I - 1, PrGr) Then
ElseIf Cells(I, PrGr) = "PrGr" Then
Else
Rows(I).EntireRow.Insert
Cells(I, 12) = "SUM " & Cells(I - 1, PrGr).Value
Cells(I, 33).Formula = "=SUMIF(R7C9:R1500C9,MID(RC12,5,255),R7C:R1500C)"
Cells(I, 34).Formula = "=SUMIF(R7C9:R1500C9,MID(RC12,5,255),R7C:R1500C)"
Cells(I, 35).Formula = "=SUMIF(R7C9:R1500C9,MID(RC12,5,255),R7C:R1500C)"
Cells(I, 36).Formula = "=SUMIF(R7C9:R1500C9,MID(RC12,5,255),R7C:R1500C)"
Cells(I, 37).Formula = "=SUMIF(R7C9:R1500C9,MID(RC12,5,255),R7C:R1500C)"
Cells(I, 38).Formula = "=SUMIF(R7C9:R1500C9,MID(RC12,5,255),R7C:R1500C)"
Cells(I, 39).Formula = "=SUMIF(R7C9:R1500C9,MID(RC12,5,255),R7C:R1500C)"
Cells(I, 40).Formula = "=SUMIF(R7C9:R1500C9,MID(RC12,5,255),R7C:R1500C)"
Cells(I, 41).Formula = "=SUMIF(R7C9:R1500C9,MID(RC12,5,255),R7C:R1500C)"
Cells(I, 42).Formula = "=SUMIF(R7C9:R1500C9,MID(RC12,5,255),R7C:R1500C)"
Cells(I, 43).Formula = "=SUMIF(R7C9:R1500C9,MID(RC12,5,255),R7C:R1500C)"
Cells(I, 44).Formula = "=SUMIF(R7C9:R1500C9,MID(RC12,5,255),R7C:R1500C)"
Rows(I).RowHeight = 17.25
I = I + 1
End If
Next
Application.CutCopyMode = True
Application.ScreenUpdating = True
End If
Cycle:
Next
Term5:
starting_ws.Activate 'activate the worksheet that was originally active
End Sub
With the insight from Vitaliy Prushak's post, I've changed that bit of code from If Cells(I, PrGr) = Cells(I - 1, PrGr) Then to If Cells(I, PrGr).Text = Cells(I - 1, PrGr).Text Then, since the cells contain text. This pushed the problem further down in the code, but it was solved with the same solution.
The macro now runs as it should, thanks for the help.
Related
I successfully wrote a code that sort through a database and looks for parts that need to be made by waterjet technique. Then, copy the associated lines with the waterjet criteria met, to another sheet named "Waterjet". It works fine, but the picture on the source sheet are not copied to the second sheet. I want to get help in finding why the pictures are not follow the cell. I checked and verified that the pictures are set to move and sized by the the cell.
Here is the code:
Sub Worksheet_Activate()
Range("A4:K2000").Select
Selection.ClearContents
Range("D1").Select
i = 4
j = 4
While i <= 2000
If Worksheets("Sheet1").Cells(i, 7) = "Waterjet" Then
p = Worksheets("Sheet1").Cells(i, 1)
q = Worksheets("Sheet1").Cells(i, 2)
r = Worksheets("Sheet1").Cells(i, 3)
s = Worksheets("Sheet1").Cells(i, 4)
t = Worksheets("Sheet1").Cells(i, 5)
u = Worksheets("Sheet1").Cells(i, 6)
v = Worksheets("Sheet1").Cells(i, 7)
w = Worksheets("Sheet1").Cells(i, 8)
x = Worksheets("Sheet1").Cells(i, 9)
y = Worksheets("Sheet1").Cells(i, 10)
Z = Worksheets("Sheet1").Cells(i, 11)
Cells(j, 1) = p
Cells(j, 2) = q
Cells(j, 3) = r
Cells(j, 4) = s
Cells(j, 5) = t
Cells(j, 6) = u
Cells(j, 7) = v
Cells(j, 8) = w
Cells(j, 9) = x
Cells(j, 10) = y
Cells(j, 11) = Z
j = j + 1
Else
End If
i = i + 1
Wend
End Sub
Source Sheet
Target Sheet - pictures are not copied
Why the images in cell "q" Cells (i,2) are not copied to cells (j,2) in the other sheet?
Edit - I just looked at your code and you're not actually copy/pasting anything, which explains why images aren't carried over.
If you also need images the maybe switch to copy/paste instead of setting values.
Sub Worksheet_Activate()
Dim i As Long, j As Long, wsData As Worksheet, shp As Shape
Me.Range("A4:K2000").ClearContents
'remove any previous shapes
For Each shp In Me.Shapes
shp.Delete
Next shp
Me.Range("D1").Select
Application.ScreenUpdating = False
Set wsData = ThisWorkbook.Worksheets("Sheet1")
j = 4
For i = 4 To wsData.Cells(Rows.Count, 7).End(xlUp).Row
If wsData.Cells(i, 7) = "Waterjet" Then
'adjust the destination row height before pasting
Me.Cells(j, 1).RowHeight = wsData.Cells(i, 1).Height
wsData.Cells(i, 1).Resize(1, 11).Copy Me.Cells(j, 1)
j = j + 1
End If
Next i
End Sub
Shapes typically are copied along with their underlying ranges. If that's not happening there's a setting you can adjust before the copy/paste operation:
Application.CopyObjectsWithCells = True
There's a checkbox for this in the Excel Options dialog.
I have a sheet that I collect the webpage data with columns from A:F
I want to put the old data in column E, from T column and onwards for each time I run the VBA module
I did for now something like
wks.Cells(i, "T").Value = wks.Cells(i, "E").Value
How can I make it to advace each time?
The full code is the following
For i = 2 To 17
LRandomNumber = Int((15 - 2 + 1) * Rnd + 2)
mylink = wks.Cells(i, 2).Value
ie.Navigate mylink
While ie.Busy Or ie.ReadyState < 4: DoEvents: Wend
t = Timer
Do
DoEvents
On Error Resume Next
wks.Range(Cells(i, 1), Cells(i, 5)).Interior.ColorIndex = 38
Set price = ie.Document.querySelector(".price-container .final-price")
myprice = CCur(price.innerText)
checkprice = myprice * 1.24
'FORMAT PRICE
If wks.Cells(i, "E").Value < checkprice Then wks.Cells(i, "E").Interior.ColorIndex = 3 Else wks.Cells(i, "E").Interior.ColorIndex = 4
wks.Cells(i, "E").Value = myprice * 1.24
Set availability = ie.Document.querySelector(".inner-box-one .availability")
wks.Cells(i, "D").Value = availability.innerText
Set product_name = ie.Document.querySelector(".title-container h1.title")
wks.Cells(i, "C").Value = product_name.innerText
If Timer - t > LRandomNumber Then Exit Do
On Error GoTo 0
Loop
If price Is Nothing Then Exit Sub
wks.Range(Cells(i, 1), Cells(i, 5)).Interior.ColorIndex = 0
Next i
We need to put
'COPY PRICE
Call TransferDataFromColumnE(wks)
Outside the For loop
Untested, but I think you could determine the last column containing data by:
Dim lastColumn as long
lastColumn = wks.cells(1, wks.columns.count).end(xltoleft).column
lastColumn = application.max(lastColumn + 1, wks.columns("T").column)
' The Application.Max is meant to guarantee you either write to column T or any column to the right of it.
' +1 is so that we don't overwrite the last column, but instead write to the column after it.
Then you could continue with your code (although it might be better/quicker to assign the entire range/column in one go rather than each cell/row individually).
wks.Cells(i, lastColumn).Value = wks.Cells(i, "E").Value
Edit: Here's a tested example. Say I have some data in column E starting on row 2 on a sheet called "Sheet2".
I can use the code below to copy-paste it to the last column (where the last column is either column T or the first empty column to the right of it).
Option Explicit
Sub TransferDataFromColumnE()
Dim wks As Worksheet
Set wks = ThisWorkbook.Worksheets("Sheet2")
Dim lastColumn As Long
lastColumn = wks.Cells(2, wks.Columns.Count).End(xlToLeft).Column
lastColumn = Application.Max(lastColumn + 1, wks.Columns("T").Column)
With wks.Range("E2:E24") ' This is the range I need to copy in my case
Dim columnOffset As Long
columnOffset = lastColumn - .Columns(1).Column
.Copy
.Offset(0, columnOffset).PasteSpecial xlPasteValuesAndNumberFormats
Application.CutCopyMode = False
End With
End Sub
And this is what I get after I've run the code three times -- which I think is what you want.
I have created some coding which is designed to loop through a data set and delete rows based on the required criteria. I need help as it deletes the first found matching criteria but doesn't loop through the rest of the data. What am I missing? Many Thanks
Sub RemoveFivePoundException()
Dim I As Integer
Dim LR As Long
Application.ScreenUpdating = False
Sheets("Claims").Select
LR = Cells(Rows.Count, "A").End(xlUp).row
Range("a1").Select
For I = 3 To LR
If Cells(I, 6).Value > 5# And Cells(I, 7) = "Under £5 write off" Then
Cells(I, 1).EntireRow.Delete
End If
Next I
Application.ScreenUpdating = True
End Sub
When deleting rows, you should invert your loop. With every row deletion the index of the next row has changed.
Alter your loop to:
For I = LR To 3 step -1 'Invert loop!
If Cells(I, 6).Value > 5# And Cells(I, 7) = "Under £5 write off" Then
Cells(I, 1).EntireRow.Delete
End If
Next I
Alternatively, you can do:
For I = 3 To LR
If Cells(I, 6).Value > 5# And Cells(I, 7) = "Under £5 write off" Then
Cells(I, 1).EntireRow.Delete
I = I - 1 'To avoid skipping rows.
End If
Next I
As per comments below this second option works, but is bad practice.
I have some excel data that comes from a lab in a strange format and am trying to figure out how to put all of the patient data on the same line. An example is below, with a single entry highlighted in red so you can see that the whole thing spans 3 lines:
I think a macro would work well for something like this but recording macros is the extent of my knowledge. I do not really know how to write VBA. The goal is to get all patient information on the same row so that they can be filtered (example below):
What I have done to figure this out on my own: I began recording a macro and manually changing things (for the recording) when I realized that the references might change depending on the heading of the worksheet, which changes. I could do a relative reference macro but then pointing the cursor to the right spot for each patient over and over is almost as much work as doing it by hand. It seemed like there should be a way to say "everything contained in three lines is one 'entry', so put on one line, starting here and ending there" or something?
How's this:
Sub text()
Dim lastRow As Integer, ageCol As Integer, addressCol As Integer, i As Integer, endRow As Integer
Dim startRow As Integer, phoneCol As Integer
lastRow = ActiveSheet.UsedRange.Rows.Count
ageCol = Rows(1).Find(what:="DOB_Age").Column
addressCol = Rows(1).Find(what:="Address").Column
phoneCol = Rows(1).Find(what:="Phone").Column
'Starting off, go to first name in the list.
startRow = Cells(1, 1).End(xlDown).Row
endRow = Cells(ActiveSheet.Rows.Count, "A").End(xlUp).Row
For i = startRow To endRow
Cells(i, 1).Select
If Cells(i, 1).Value <> "" Then
Cells(i, ageCol).Value = Cells(i, ageCol).Value & " " & Cells(i, ageCol).Offset(1, 0).Value
Cells(i, addressCol).Value = Cells(i, addressCol).Offset(-1, 0).Value & ", " & Cells(i, addressCol).Value & ", " & Cells(i, addressCol).Offset(1, 0).Value
Cells(i, phoneCol).Value = Cells(i, phoneCol).Offset(1, 0).Value
' Now, let's clear the data we copied over.
Cells(i, ageCol).Offset(1, 0).Value = ""
Cells(i, addressCol).Offset(-1, 0).Value = ""
Cells(i, addressCol).Offset(1, 0).Value = ""
Cells(i, phoneCol).Offset(1, 0).Value = ""
End If
Next i
'Now, let's delete all the empty rows
For i = 1 To endRow
If i > endRow Then Exit For
If IsEmpty(Cells(i, 1)) Then
Cells(i, 1).EntireRow.Delete
i = i - 1
endRow = Cells(ActiveSheet.Rows.Count, "A").End(xlUp).Row
End If
Next i
End Sub
Note: This assumes that your data will always look like your question - the row with a name on it has ONE row above and ONE row below that need to be moved to the name's row. Please let me know what works/what doesn't work and needs tweaking. Good luck!
Multiple Formula (Non-VBA) Solution:
This option would be to get the values to appear in another sheet using formulas and autofilling down.
Note: this option assumes that all your data is as shown in the images, currently I do not account for any exceptions (which can be added)
Here are the formulas (using "Sheet1" as the reference sheet, change that to whatever your sheet name is):
(Horizontal view, ..have fun scrolling..)
A B C D E F
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1| Id Patient_Name Sex DOB_Age Address Phone
2| =INDIRECT("Sheet1!A"&(ROW()-1)*3) =INDIRECT("Sheet1!B"&(ROW()-1)*3) =INDIRECT("Sheet1!C"&(ROW()-1)*3) =TEXT(INDIRECT("Sheet1!D"&(ROW()-1)*3),"m/d/yyy")&", "&INDIRECT("Sheet1!D"&(ROW()-1)*3+1) =INDIRECT("Sheet1!E"&(ROW()-1)*3-1)&", "&INDIRECT("Sheet1!E"&(ROW()-1)*3)&", "&INDIRECT("Sheet1!E"&(ROW()-1)*3+1) =INDIRECT("Sheet1!F"&(ROW()-1)*3+1)
3| ..Autofill down..
(Vertical view)
Id
=INDIRECT("Sheet1!A"&(ROW()-1)*3)
Patient_Name
=INDIRECT("Sheet1!B"&(ROW()-1)*3)
Sex
=INDIRECT("Sheet1!C"&(ROW()-1)*3)
DOB_Age
=TEXT(INDIRECT("Sheet1!D"&(ROW()-1)*3),"m/d/yyy")&", "&INDIRECT("Sheet1!D"&(ROW()-1)*3+1)
Address
=INDIRECT("Sheet1!E"&(ROW()-1)*3-1)&", "&INDIRECT("Sheet1!E"&(ROW()-1)*3)&", "&INDIRECT("Sheet1!E"&(ROW()-1)*3+1)
Phone
=INDIRECT("Sheet1!F"&(ROW()-1)*3+1)
Now since these are formulas and not vba, the data will automatically change if the source changes. So if you want to only keep the values you can copy -> paste special -> values on a new sheet to keep only the values
Sub Parse_Data()
Dim rngTarget As Range, x As Long
Set rngTarget = Worksheets("Target").Range("A2")
For x = 2 To Range("E1").Offset(Rows.Count - 1).End(xlUp).Row
Select Case x Mod 3
Case 2
rngTarget.Offset(, 5).Value = Range("A1").Offset(x - 1, 4).Value
Case 0
rngTarget.Offset(, 0).Value = Range("A1").Offset(x - 1, 0).Value
rngTarget.Offset(, 1).Value = Range("A1").Offset(x - 1, 1).Value
rngTarget.Offset(, 2).Value = Range("A1").Offset(x - 1, 2).Value
rngTarget.Offset(, 3).Value = Range("A1").Offset(x - 1, 3).Value
rngTarget.Offset(, 6).Value = Range("A1").Offset(x - 1, 4).Value
Case 1
rngTarget.Offset(, 4).Value = Range("A1").Offset(x - 1, 3).Value
rngTarget.Offset(, 7).Value = Range("A1").Offset(x - 1, 4).Value
rngTarget.Offset(, 8).Value = Range("A1").Offset(x - 1, 5).Value
Set rngTarget = rngTarget.Offset(1)
End Select
Next x
End Sub
apologize if this is a common post, but couldn't find something that fully applies to me.
It's a very similar post to (except that instead of just merging the 2 cells, i am looking to merge and concatenate):
Macro to merge cells in Excel for rows in which information in other columns matches
Referencing the image in the post above, what i am looking for are cells P2 and P3 to be merged and the data to be concatenated. For eg: if P2 had abc, and P3 had xyz, i am looking for end product to be abcxyz in the merged cell.
Any help would be greatly appreciated. What i have only enables me to merge, but i am not sure how to concatenate it.
Sub Main()
Dim i As Long
Dim j As Long
Dim sameRows As Boolean
sameRows = True
For i = 1 To Range("A" & Rows.Count).End(xlUp).Row
For j = 1 To 6
If StrComp(Cells(i, j), Cells(i + 1, j), vbTextCompare) Then
sameRows = False
End If
Next j
If sameRows Then
Range(Cells(i, 7), Cells(i + 1, 7)).Merge
End If
sameRows = True
Next i
End Sub
simply add this line in the code:
Cells(i, 7).Value = Cells(i, 16).Text + Cells(i + 1, 16).Text
complete code:
Sub merge()
Dim i As Long
Dim j As Long
Dim sameRows As Boolean
sameRows = True
For i = 1 To Range("A" & Rows.Count).End(xlUp).Row
For j = 1 To 6
If StrComp(Cells(i, j), Cells(i + 1, j), vbTextCompare) Then
sameRows = False
End If
Next j
If sameRows Then
Range(Cells(i, 7), Cells(i + 1, 7)).merge
Cells(i, 7).Value = Cells(i, 16).Text + Cells(i + 1, 16).Text
End If
sameRows = True
Next i
End Sub
The solution is pretty straightforward: you store the first String inside a variable,
Dim FinalText As String
FinalText = Cells(i, 7).Text
add the second String
FinalText = FinalText & Cells(i + 1, 7).Text
then after merging the two cells, you write the content of the variable in your merged cell.
Cells(i, 7) = FinalText
I'm not going to give you the full solution though, since you copy-pasted what you found and wouldn't try to write something by yourself.
EDIT: if more than one cell is to be merged, I'd use the same technique, but using FinalText = FinalText & Cells(i + 1, 7).Text inside the condition that checks if the values contained in each cell is equal...