I built a COVID model using UVA data. That data is currently unavailable so I've found another data source. Of course, the new data is not in the same format. So rather than starting from scratch, I'm importing the new data in the format the model was coded for. The new data looks like this...
The new data files are broken up into a Confirmed file, a Deaths file and a Recovered file. Each file is 267 rows and goes out to column EH with a new column added daily. I have a macro for each file. The Confirmed file takes about a minute - minute and a half to run. And when done it looks like this...
I don't import any of the confirmed = 0 data points. I've added the population/pop density columns to delete all the countries I don't care about (those with population = 0). This file has about 6800 rows and of course, this will also grow daily. When the Confirmed file is imported, of course the next thing is Deaths. When I try to import the Deaths file excel goes to 'Not Responding' state and doesn't finish. I've waited on the Deaths macro for about an hour before I killed it and it's still not done. I can see that the correct numbers are being put into the correct column in my consolidated file but it really shouldn't take so long or lock up excel like this. I realize that three For Loops is going through a lot of cells a lot of times. Is there a better way to do this?
Here is the Deaths import code:
Sub ImportCSSEDeaths()
Dim i As Variant
Dim j As Variant
Dim k As Variant
Dim lastrow As Long
Dim clastrow As Long
Dim lastcol As Long
Dim dte As Date
Dim filePath As String
Dim wb As Excel.Workbook
Dim ws As Excel.Worksheet
Dim cws As Excel.Worksheet
Set cws = ThisWorkbook.Sheets("Raw_Data")
lastrow = cws.Cells(Rows.count, "a").End(xlUp).Row
filePath = "C:\Users\chris.h\Desktop\COVID\Other_Data\CSSE\CSSE_Deaths.xlsx"
Set wb = Excel.Workbooks.Open(filePath)
Set ws = wb.Worksheets(1)
clastrow = cws.Cells(Rows.count, "b").End(xlUp).Row
lastrow = ws.Cells(Rows.count, "b").End(xlUp).Row
lastcol = ws.Cells(1, Columns.count).End(xlToLeft).Column
For i = 2 To clastrow
For j = 2 To lastrow
For k = 3 To lastcol
If cws.Cells(i, "a").Value = ws.Cells(j, "a").Value And _
cws.Cells(i, "b").Value = ws.Cells(j, "b").Value And _
cws.Cells(i, "c").Value = ws.Cells(1, k).Value Then
cws.Cells(i, "e").Value = ws.Cells(j, k).Value
cws.Cells(i, "e").NumberFormat = "#,##0"
End If
Next k
Next j
Next i
wb.Close False
End Sub
If more code is needed, I'll provide.
Thanks to #Tom and #Nacorid the following array based code works much faster! Only takes a min or two.
k = 0
For i = 2 To lastrow
For j = 3 To lastcol
'puts country row deaths into array
If ws.Cells(i, j).Value <> 0 Then
ReDim Preserve deaths(k)
deaths(k) = ws.Cells(i, j).Value
k = k + 1
End If
Next j
'finds startdate in new data
For j = 3 To lastcol
If deaths(0) = ws.Cells(i, j).Value Then
startDate = ws.Cells(1, j).Value
Exit For
End If
Next j
Debug.Print startDate
clastrow = cws.Cells(Rows.count, "b").End(xlUp).Row
'finds startdate in compiled data and enters array values down column e
For j = 2 To clastrow
If cws.Cells(j, "a").Value = ws.Cells(i, "a").Value And _
cws.Cells(j, "b").Value = ws.Cells(i, "b") And _
cws.Cells(j, "c").Value = startDate Then
count = j
For k = 0 To UBound(deaths)
cws.Cells(count, "e").Value = deaths(k)
count = count + 1
Next k
End If
Next j
Next i
Related
This should be an easy problem to solve, but I am extremely unfamiliar with VBA so I need some help.
Essentially, I want to copy data given to me (finite column range, but dynamic rows), and paste it transposed into a second sheet within excel. From there, I need to convert all the values in columns D,E,F, and H to fractions out of 12. I'm pretty sure I'm 99% of the way there, but the last step (converting to fraction text) is being performed in the wrong worksheet. I've tried using the .Activate function as well as setting the correct worksheet, but neither work. There's got to be an easy fix to this that I'm missing. Note: this is my first time ever coding in VBA so take it easy on me. Code is below:
Option Explicit
Sub FormatData()
Dim ws As Worksheet
' create a new worksheet, and name it "Master"
Set ws = ThisWorkbook.Worksheets.Add(after:=ThisWorkbook.Worksheets(1))
ws.Name = "Master"
' copy the UsedRange and Transpose
Worksheets("Sheet1").UsedRange.Copy
ws.Range("A1").PasteSpecial xlPasteAll, Transpose:=True
Sheets("Master").Activate
Dim i As Long, N As Long, j As Long
N = Cells(Rows.Count, "D").End(xlUp).Row
j = 2
For i = 2 To N
Cells(i, "D") = WorksheetFunction.Text(Cells(i, "D"), "0 0/12")
j = j + 1
Next i
j = 2
For i = 2 To N
Cells(i, "E") = WorksheetFunction.Text(Cells(i, "E"), "0 0/12")
j = j + 1
Next i
j = 2
For i = 2 To N
Cells(i, "F") = WorksheetFunction.Text(Cells(i, "F"), "0 0/12")
j = j + 1
Next i
j = 2
For i = 2 To N
Cells(i, "H") = WorksheetFunction.Text(Cells(i, "H"), "0 0/12")
j = j + 1
Next i
End Sub
first only do only one loop and do all four conversions inside that one loop. Second, j is not doing anything, you can omit it.
Sub FormatData()
Dim ws As Worksheet
' create a new worksheet, and name it "Master"
Set ws = ThisWorkbook.Worksheets.Add(after:=ThisWorkbook.Worksheets(1))
With ws
.Name = "Master"
' copy the UsedRange and Transpose
Worksheets("Sheet1").UsedRange.Copy
.Range("A1").PasteSpecial xlPasteAll, Transpose:=True
Dim i As Long, N As Long
N = .Cells(.Rows.Count, "D").End(xlUp).Row
For i = 2 To N
.Cells(i, "D") = Application.WorksheetFunction.Text(.Cells(i, "D"), "# ??/12")
.Cells(i, "E") = Application.WorksheetFunction.Text(.Cells(i, "E"), "# ??/12")
.Cells(i, "F") = Application.WorksheetFunction.Text(.Cells(i, "F"), "# ??/12")
.Cells(i, "H") = Application.WorksheetFunction.Text(.Cells(i, "H"), "# ??/12")
Next i
End With
End Sub
Based on the earlier thread that i posted, How do i extract merged data and put them into different worksheets? Everything seems fine until my program encounter the
"program not responding error"
which I think is due to using
Sheets(sheetname).UsedRange.Rows.count
(because of deleting and clearing rows) which cause this to happen. Based on other thread discussions, I tried to use this instead
Cells(Sheets("SheetName").Rows.Count, 1).End(xlup).Row
(better options as suggested by others) but it didnt give me the result that I want which is as shown below. So how do I modify my below code to solve the program not responding error in this case and still get the ideal scenario as shown below?
Put the extracted data into 3 different sheets namely index 1, index 2 and index 3 as shown below
Sub UpdateVal()
Static count As Long
Dim iRow As Long
Dim aRow As Long
Dim a As Long
Dim b As Long
Dim selectRange As Range
dim lastline as integer
dim sheetname as string
dim indexrowcount as integer
dim wb as workbook
dim ws as worksheet
set wb= activeworkbook
set ws=wb.sheets(Index)
j = 2
iRow = 1
LastLine = ActiveSheet.UsedRange.Rows.count
While iRow < LastLine + 1
a = iRow + 1
b = iRow + 17 ' Max Group Size with Same name in F to H column
count = 1
If ws.Cells(iRow, "F").Value = "Martin1" Then
sheetname = "Index1"
ElseIf ws.Cells(iRow, "F").Value = "John1" Then
sheetname = "Index2"
Else
sheetname = "Index3"
End If
For aRow = a To b
If ws.Cells(iRow, "F") = ws.Cells(aRow, "F") And ws.Cells(iRow, "G") = ws.Cells(aRow, "G") And ws.Cells(iRow, "H") = ws.Cells(aRow, "H") Then
count = count + 1
Else
Set selectRange = Range("A" & iRow & ":J" & aRow - 1)
selectRange.Copy
indexrowcount = Sheets(sheetname).UsedRange.Rows.count
Sheets(sheetname).Range("A" & indexrowcount).PasteSpecial xlPasteAll
iRow = iRow + count
Exit For
End If
Next aRow
Wend
My guess is that your Implicit sheet references could be the culprit. As mentioned in my comment, Implicit references will refer to the currently active sheet, or ActiveSheet.
Have a look at this post on how to avoid that. When you studied that post, you should have a Worksheet variables, for exmple ws to refer to.
Right now, If Cells(iRow, "F") = Cells(aRow, "F") And Cells(iRow, "G") = Cells(aRow, "G") And Cells(iRow, "H") = Cells(aRow, "H") Then could be TRUE on any ActiveSheet with all empty cells for example. That way you will never hit FALSE and iRow never gets incremented > Endless loop > Your error!
I am not sure if the title is correct. Please correct me if you have a better idea.
Here is my problem: Please see the picture.
This excel sheet contains only one column, let's say ColumnA. In ColumnA there are some cells repeat themselvs in the continued cells twice or three times (or even more).
I want to have the excel sheet transformed according to those repeated cells. For those items which repeat three times or more, keep only two of them.
[Shown in the right part of the picture. There are three Bs originally, target is just keep two Bs and delete the rest Bs.]
It's a very difficult task for me. To make it easier, it's no need to delete the empty rows after transformation.
Any kind of help will be highly appreciated. Thanks!
#
Update:
Please see the picture. Please dont delete the items if they show again...
EDITED - SEE BELOW Try this. Data is assumed to be in "Sheet1", and ordered data is written to "Results". I named your repeted data (A, B, C, etc) as sMarker, and values in between as sInsideTheMarker. If markers are not consecutive, the code will fail.
Private Sub ReOrderData()
Dim lLastRow As Long
Dim i As Integer
Dim a As Integer
Dim j As Integer
Dim sMarker As String
Dim sInsideTheMarker As String
'Get number of rows with data:
lLastRow = Worksheets("Sheet1").Cells(Rows.Count, 1).End(xlUp).Row
j = 0
k = 1
a = 2
'Scan all rows with data:
For i = 1 To lLastRow
If (Worksheets("Sheet1").Cells(i + 1, 1).Value = Worksheets("Sheet1").Cells(i, 1).Value) Then 'If two consecutive cells holds the same value
j = j + 1
If j = 1 Then
k = k + 1
a = 2
sMarker = Worksheets("Sheet1").Cells(i, 1).Value
Worksheets("Results").Cells(k, 1).Value = sMarker
End If
Else 'If not same values in consecutive cells
sInsideTheMarker = Worksheets("Sheet1").Cells(i, 1).Value
Worksheets("Results").Cells(k, a).Value = sInsideTheMarker
a = a + 1
j = 0
End If
Next i
End Sub
EDITION: If you want results in the same sheet ("Sheet1"), and keep the empty rows for results to look exactly as your question, try the following
Private Sub ReOrderData()
Dim lLastRow As Long
Dim i As Integer
Dim a As Integer
Dim j As Integer
Dim sMarker As String
Dim sInsideTheMarker As String
'Get number of rows with data:
lLastRow = Worksheets("Sheet1").Cells(Rows.Count, 1).End(xlUp).Row
j = 0
k = 1
a = 5
'Scan all rows with data:
For i = 1 To lLastRow
If (Worksheets("Sheet1").Cells(i + 1, 1).Value = Worksheets("Sheet1").Cells(i, 1).Value) Then 'If two consecutive cells holds the same value
j = j + 1
If j = 1 Then
k = i
a = 5
sMarker = Worksheets("Sheet1").Cells(i, 1).Value
Worksheets("Sheet1").Cells(k, 4).Value = sMarker
End If
Else 'If not same values in consecutive cells
sInsideTheMarker = Worksheets("Sheet1").Cells(i, 1).Value
Worksheets("Sheet1").Cells(k, a).Value = sInsideTheMarker
a = a + 1
j = 0
End If
Next i
End Sub
If you can delete the values that have more than two counts, then I suggest that this might work:
Sub count_macro()
Dim a As Integer
Dim b As Integer
a = 1
While Cells(a, 1) <> ""
b = WorksheetFunction.CountIf(Range("A1:A1000"), Cells(a, 1))
If b > 2 Then
Cells(a, 1).Delete Shift:=xlUp
End If
b = 0
a = a + 1
Wend
End Sub
This should do it. It takes input in column A starting in Row 2 until it ends, and ignores more than 2 same consecutive values. Then it copies them in sets and pastes them transposed. If your data is in a different column and row, change the sourceRange variable and the i variable accordingly.
Sub SETranspose()
Application.ScreenUpdating = False
Dim sourceRange As range
Dim copyRange As range
Dim myCell As range
Set sourceRange = range("A2", Cells(Rows.count, 1).End(xlUp))
Dim startCell As range
Set startCell = sourceRange(1, 1)
Dim i As Integer
Dim haveTwo As Boolean
haveTwo = True
For i = 3 To Cells(Rows.count, 1).End(xlUp).Row + 1
If Cells(i, 1).Value = startCell.Value Then
If haveTwo Then
range(startCell, Cells(i, 1)).Copy
startCell.Offset(0, 4).PasteSpecial Transpose:=True
Application.CutCopyMode = False
haveTwo = False
End If
End If
'if the letter changes or end of set, then copy the set over
'If LCase(Left(Cells(i, 1).Value, 1)) <> LCase(startCell.Value) Or _
'i = Cells(Rows.count, 1).End(xlUp).Row + 1 Then
If Len(Cells(i, 1).Value) > 1 Then
Set copyRange = Cells(i, 1)
copyRange.Copy
Cells(startCell.Row, Columns.count).End(xlToLeft).Offset(0, 1).PasteSpecial
Application.CutCopyMode = False
'Set startCell = sourceRange(i - 1, 1)
ElseIf Len(Cells(i, 1).Value) = 1 And Cells(i, 1).Value <> startCell.Value Then
Set startCell = sourceRange(i - 1, 1)
haveTwo = True
End If
Next i
'clear up data
Set sourceRange = Nothing
Set copyRange = Nothing
Set startCell = Nothing
Application.ScreenUpdating = True
End Sub
I have to create a vba script that takes data from a column of another table in Excel ("Days Of Last Update", which is decimal), and then makes a sum based if the day are above 2 (showing the result in a new column).
It seems to be very simple, but I am a beginner and have no idea how to proceed.
UPDATE:
Hello everyone, thanks for the help. Now I have a new problem, still in this project. Here is what I've done:
The RawData's sheet have a column named "Days Since Last Update", that tells me when the Service Request of the product is updated. So, I created a new column with this formula =IF(N:N>2,1,0), to tells me if the Days Since Last Updated are above 2. I refreshed my pivot table to get this new column, did a Sum of the data, and get what I previously wanted, but, when the Update function of the worksheet run, the new column of the pivot table, as well as the column of the RawData with the formula, are gone. In the code (that isn't done by me) of the Update function, there was something like this:
Worksheets("Pivot table").PivotTables("PivotTable1").PivotCache.Refresh
It has something to do with my problem?
Please find the sample data sheet appended below.
VBA Code is appended below.
Sub Extract_Values()
Dim wks As Worksheet
Dim startRow As Integer
Dim lastRow As Integer
Dim vArray As Variant
Dim vNewArray As Variant
Dim i As Integer, j As Integer
Dim Counter1 As Integer, Counter2 As Integer
startRow = 2
Set wks = Sheets("Sheet1")
With wks
lastRow = .Cells(Rows.Count, 1).End(xlUp).Row
vArray = .Range("A" & startRow & ":D" & lastRow).Value2
For i = 1 To UBound(vArray)
If vArray(i, 4) = "Y" Then
Counter1 = Counter1 + 1
End If
Next i
ReDim vNewArray(1 To Counter1, 1 To 2)
For j = 1 To UBound(vArray)
If vArray(j, 4) = "Y" Then
Counter2 = Counter2 + 1
vNewArray(Counter2, 1) = vArray(j, 1)
vNewArray(Counter2, 2) = vArray(j, 2)
End If
Next
End With
Range("E" & startRow & ":F" & startRow + Counter1 - 1) = vNewArray
Range("E" & startRow & ":E" & startRow + Counter1 - 1).Select
Selection.NumberFormat = "m/d/yyyy"
Range("F" & startRow + Counter1).Select
End Sub
I am also a beginner setting proper VBA code in cell F8 which I have calculated Excel in-built Count Function.
COLUMN D Contains IF Formula like 'D2=IF(B2>1,"Y","N")'
HTH
Try
Dim RowCount As Integer
Dim NewRow As Integer
RowCount = 2
NewRow = 2
Do Until RowCount > Cells(2, 2).End(xlDown).Row
If Cells(RowCount, 2) > 1 Then
Range(Cells(NewRow, 5), Cells(NewRow, 6)).Value = Range(Cells(RowCount, 1), Cells(RowCount, 2)).Value
NewRow = NewRow + 1
End If
RowCount = RowCount + 1
Loop
End Sub
I am uploading a Tabular data into my SQL database.
The following is the original look of the data.
I want to take each temperature (Y axis) in a column and then each gravity (X Axis) in next Column, followed by the intersecting value.
Like This:
i got helped from a guy from ExcelForum. Here is the Macro Code, that solved my problem.
Option Explicit
Sub transpose_data()
Dim lrow As Long, lcol As Long, a As Long, i As Long, j As Long
Worksheets.Add(after:=Worksheets(Worksheets.Count)).Name = "Output"
a = 1
With Worksheets("Original")
lrow = .Range("A" & .Rows.Count).End(xlUp).Row
lcol = .Range("IV1").End(xlToLeft).Column
For i = 2 To lrow
For j = 2 To lcol
Worksheets("Output").Cells(a, 1).Value = .Cells(i, 1).Value
Worksheets("Output").Cells(a, 2).Value = .Cells(1, j).Value
Worksheets("Output").Cells(a, 3).Value = .Cells(i, j).Value
a = a + 1
Next j
Next i
End With
Worksheets("Output").Columns("A:C").NumberFormat = "0.00"
End Sub
Make sure to change the Sheet name to 'Original' in order to have this code working.