Delete entire row based on part of the value of a cell - excel

I have spreadsheets that list the dates in column A, ex 12/1/2016 1:45:00 AM. I reformat all the cells in this column so they display Day, Month #, Year. Example Thursday, December 01, 2016. The Find function works if I click on the actual find button and search for the values, however I am struggling to code this. I want to delete all the rows that contain "Saturday" and "Sunday". The latest code I have tried is as follows;
Last = Cells(Rows.Count, "D").End(xlUp).Row
For i = Last To 1 Step -1
If (Cells(i, "D").Value) = "*Saturday*" Then
Cells(i, "A").EntireRow.Delete
End If
Next i
I have also tried the following code as well;
Set Find = Range("A:A").Find("Saturday", LookIn:=xlValues)
Do Until Find Is Nothing
Find.EntireRow.Delete
Set Find = Range("A:A").FindNext
Loop

Set the LookAt Parameter to xlPart
Find("Saturday", , , xlPart)

Change
If (Cells(i, "D").Value) = "*Saturday*" Then`
to
If (Cells(i, "D").Text) Like "*Saturday*" Then
Using Text instead of Value will access the displayed value, rather than the underlying value (which is a date), and using Like instead of = will allow wildcards to work.
Your question is confusing as to which column the dates are in. Some of your code (and your question) suggests they are in column A, but other parts of your code suggest column D. If they are in column A, change the code above to use "A" instead of "D".

Related

Retain formatting on a used value

There are two sheets, one containing columns with date ranges ("Test" sheet), the other containing payment amounts with specific dates ("Payment information" sheet).
I wrote code, that goes line by line in the second sheet and checks if the date falls between a date range in the first based on supplier values existing in both sheets.
Where I am stuck:
Payment amounts contain formatting for currencies e.g. €, $ or different. If I use something like the code below - it retains the formatting, however: the same cell in "Test" sheet, might have to have the sum of multiple lines from "Payment information" and copy pasting replaces the values.
ThisWorkbook.Sheets("Payment information").Cells(i, "F").Copy
ThisWorkbook.Sheets("Test").Cells(last_row, j).PasteSpecial xlPasteValuesAndNumberFormats
If alternatively I use the code below - the formatting drops off:
payment_amount = ThisWorkbook.Sheets("Payment information").Cells(i, "F")
ThisWorkbook.Sheets("Test").Cells(last_row, j).value = ThisWorkbook.Sheets("Test").Cells(last_row, j).value + payment_amount
From what I understand, you can do a PasteSpecial xlformats to just copy those.
So going from
Range("A1").Copy
Range("A2").PasteSpecial xlFormats
On your example:
ThisWorkbook.Sheets("Payment information").Cells(i, "F").Copy
ThisWorkbook.Sheets("Test").Cells(last_row, j).PasteSpecial xlFormats
Adding from your comment below, you should use a variable that adds value when it meets conditions.
For example
Dim payment as Integer
Select case Range("A2").Value
Case #1/1/2022# To #12/31/2022#
payment = payment + Range("A2")
Case else
payment = Range("A2").Value
So the code goes like this: If it happens to be in 2022, it adds the value to your variable.
If it's not in 2022, it copies the value
You then can paste/show the value in your desired range, like:
Range("A2").Value = payment
Combining it with an iteration to check dates and it should work.
Hope it helps!

Change countif range using vba

I would like to change the range in the counfif-formula by using vba. By clicking a button the Range A3:A3 changes to A3:A4, then clicking the button again A3:A4 changes to A3:A5, and so on... I managed to create a constant vba-formula, but I do not know how to proceed. Anybody? :)
Excel
VBA
I think you need a dummy cell/value to achieve, The dummy cell will "count" how many times you have clicked the button. My solution will require a dummy cell.
Sub Countif_function()
Dim start_value As Long
start_value = Cells(1, "D").Value 'Take the value from cell D1
If start_value <= 3 Or Cells(1, "D").Value = "" Then start_value = 3 ' If the value is less than 3 (since you start at row 3) or if the value is empty then set the minimum start value to 3 (otherwise countif will fail).
Cells(3, "D").Value = Application.WorksheetFunction.countif(Range(Cells(3, "A"), Cells(start_value, "A")), "A") 'Using the inbuild function in VBA to retrieve the countif
Cells(3, "E").Value = "=COUNTIF(A3:A" & start_value & ",""A"")" 'Just for view purpose of the final formula result, can be ignored in the code
Cells(1, "D").Value = Cells(1, "D").Value + 1 'Add +1 row. This will be used as the start value for next time the code is executed.
End Sub
I used "A" as criteria since you used it in your example code, but could be change to "C3" or some other cell.
Result:
The alternate if you don't want a dummy cell to count as per the previous answer is to read the formula in the cell into a string variable via range.formula, split it on the comma, read the last digit of the first entry in the split array, increment by 1. (If the digit is a 9, then check whether the preceding character is a number or letter, if letter, make the 9 a 10, if number, increment that by one and make the 9 a 0, if the preceding character is also a 9, recursive call). So, yeah, unless you really cannot have the dummy cell, use that solution, it's easier.

Replicating values

Need a little help here.
In the "Data" Tab I want to copy values in column "c2:c1000" and paste in column "a1" of another Tab.
This is what i have so far,
Dim x As Long
Dim lastRow As Long
lastRow = Worksheet("Data").Cells(3, Columns.Count).End(xlUp).Column
For x = 1 To lastRow
If Worksheets("Sheet2").Cells(2, "A") = "" Then
Worksheets("Data").Range("c2:c1000").Copy Destination:=Worksheets("Sheet2").Range(1, "A")
Sheets("Sheet2").Range("A1").Value = Format(Now, "mm/dd/yyyy HH:mm:ss")
Else
Worksheets("Data").Range("c2:c1000").Copy Destination:=Worksheets("Sheet2").Cells(2,
Columns.Count).End(xlToLeft).Offset(, 1)
'Sheets("Sheet2").Range("A1").Value = Format(Now, "mm/dd/yyyy HH:mm:ss") --> can't figure how to increment this as this will need to be on the subsequent empty column
End If
Next
End Sub
Your help will be greatly appreciated!
Thank you.
Pasting values first into range A1 and down and then next time to cell B1 and so on, leaves no space for the timestamp to A1, B1 etc. So, I assume that you would like to paste the random values to row 2. So cells A1, B1, ... are left for the timestamp.
Inside the With statements we can refer to properties of the wsAudit so we can replace the "Worksheets("Audit")." reference with just "."
The column.count expression just checks the amount of columns in the worksheet.
The expression .Cells(2, Columns.Count) just points to last cell in the row 2.
The .End(xlToLeft).Column then looks from this column to left and is supposed to find the last not empty cell on this row. It's basically the same idea that in Excel's sheet you would go to cell XDF2 and hit CTRL+Arrow Left from keyboard.
But instead of activating the cell we just want to get the columns index number and then add 1 (the new column) and save it into variable. Now the new column is known.
The expression Range(.Cells(2, newColAudit), .Cells(1000, newColAudit)).Value is really the same as e.g. Range("B2:B1000"), but with this we can use the row and column index numbers instead. This is useful as the column number varies.
And as Samuel pointed out the copy paste operation can be avoided by setting the areas equal.
Dim wsAudit As Worksheet
Dim newColAudit As Long
Set wsAudit = Worksheets("Audit")
With wsAudit
newColAudit = .Cells(2, Columns.Count).End(xlToLeft).Column + 1
Range(.Cells(2, newColAudit), .Cells(1000, newColAudit)).Value = Worksheets("Data").Range("C2:C1000").Value
.Cells(1, newColAudit).Value = Format(Now, "mm/dd/yyyy HH:mm:ss")
End With
Much like your LastRow* variable for your source sheet, create a LastColumn variable for your destination sheet, which will find the last used column the same way you are finding your last used row.
Like so:
Dim LastColumn As Long
LastColumn = Sheets("Audit").Cells(1, Columns.Count).End(xlToLeft).Column
Then use the variable like so:
Destination:= Worksheets("Audit").Cells(1, LastColumn)
It seems that your code contradicts your question too, in your question you explained the data will be written to the Audit sheet in row 1, using the next column each time but your code looks for values in row 2 in your If statement:
If Worksheets("Audit").Cells(2, "A") = "" Then is the same as If Worksheets("Audit").Range("A2") = "" Then.
If you mean to check the first row, change the 2 to 1.
To help improve your codes efficiency:
(Also see the link to 'how to avoid select' in that question):
You can achieve 'copy/paste' without actually using the 'copy' and 'paste' methods by assigning the value of one range to the other, as example, like so:
Worksheets("Audit").Cells(1, LastColumn).Resize(999, 1) = Worksheets("Data").Range("c2:c1000").Value
Note: Change the Resize Property rows to suit the source range (in this case you are wanting to move values from C2:C1000).
*The LastRow variable is a bit confusing, as it is looking for the last used column in row 3.
If it's meant to find a column, consider renaming it to avoid confusion later on in debugging.
If it's meant to find the last row, try like this:
LastRow = Worksheet("Data").Cells(Rows.Count, 1).End(xlUp).Row

Copy/paste dates exactly as displayed? Not necessarily the format, but as they're displayed visually

I can't seem to figure out how to overwrite my date with what's being displayed.
For example, what's being displayed is 06/01/2016, but the actual data behind that is showing 01/06/2016. The date I want to have in there is June 1, 2016 (which is what's displayed). Changing the format of the cell doesn't help, because I'm doing some formulas with the Dates later, so actually need to have Excel have the correct date.
I have about 10,000 of such dates, where the displayed date is exactly what I want to have, but the actual formula "reversed".
Essentially, I would love to just copy that column (or run a sub) that puts what the cell literally displays into the cell.
What sort of works is doing this, but it only works on those cells with "backwards" dates...essentially passing the day as a month, and month as a day.
=DATE(YEAR(C1),DAY(C1),MONTH(C1)).
It "falls apart" though when the date is actually correct and I don't want it to change:
So, what'd be best is to just literally overwrite the cell with what's displayed.
Or, what would an IF statement be that I could use to somehow check if the date displayed is what I want, and if so keep that, otherwise use that =DATE(YEAR(),DAY(),MONTH()) "trick"?
I also tried =IF(DAY(C2)>12,DATE(YEAR(C2),DAY(C2),MONTH(C2)),C2) but that doesn't work either because it returns June 01 2016 for both 01/06/2016 and 06/01/2016.
I may be overlooking something simple, I've been staring at this for an hour or so...Any thoughts/ideas are appreciated!
Say wee have dates in column C from C1 through C100 that appear to be correct. (so if you see 06/12/2017 you want it to be June 12th and not December 6th)
Try this short macro:
Sub dateFixer()
Dim ary(1 To 100) As String
Dim rng As Range, r As Range
Dim i As Long
Set rng = Range("C1:C100")
i = 1
For Each r In rng
ary(i) = r.Text
i = i + 1
Next r
rng.Clear
rng.NumberFormat = "mm/dd/yyyy"
i = 1
For Each r In rng
r.Value = ary(i)
i = i + 1
Next r
End Sub
A really clean solution is to use the CELL() function.
=CELL("format",A1) will return "D1" for cells formatted as d/m/y, and "D4" for cells formatted m/d/y. So, with this you can conditionally flip month and day:
=IF(CELL("format",A2)="D1",DATE(YEAR(A2),DAY(A2),MONTH(A2)),A2)
The Text property of a range returns the display text: "what the cell literally displays."
Note that literal is the right word - for example, if your column is too narrow, Text will return the displayed ##### characters instead of any useful value.
The Text property will not return an array, so you'll have to loop through your range and read/write individual cells with something like this:
For Each c in rng
c.Value = c.Text
Next c
Incidentally, the documentation on this property is almost nonexistent. This blog post goes into a more detailed review of the property and how it relates to Value and Value2.

VBA counter based on date

I have created a userform to track service requests and I am having trouble with this last part.
There are 2 columns in question the first "A" is service ID the second is "B" Date. I want "B" to be today's date and "A" to start at 1 and count up, when I add a new request tomorrow I want "A" to start at 1 again.
Here is the code for column "A", when a new record is created "A" goes up but when the date changes it does not start back at 0. Any ideas?
'Service ID
'check row above
'if "Date" then out put "1"
'if yesterday then out put "1"
'if today then ouput + 1
If (Sheet1.Cells(Rows.Count, "B").End(xlUp).Value) = "Date" Then
serviceorder = "1"
ElseIf (Sheet1.Cells(Rows.Count, "B").End(xlUp).Value) < Date Then
serviceorder = "1"
ElseIf (Sheet1.Cells(Rows.Count, "B").End(xlUp).Value) = Date Then
serviceorder = (Sheet1.Cells(Rows.Count, "A").End(xlUp).Value) + 1
Else
End If
Thanks in advance.
Why not just make column A a COUNTIF formula to show the number of times the date in the corresponding column B cell shows up in all of column B? That way when the date changes, it will auto reset to 1 and each new time a request is entered the same day, it the ID will increment by 1. The VBA formula would be:
With Sheet1.Cells(Rows.Count, "A").End(xlUp).Offset(1)
.Formula = "=COUNTIF(B:B,B" & .Row & ")"
'Uncomment this next line if you want column A to contain values instead of formulas
'If you do uncomment it, make sure you have already put the date in the B column for this entry
'.Value = .Value
End With
I think the general problem in your functions is the Sheet1.Cells(Rows.Count, "B").End(xlUp). Rows.Count means - as it says - the count of rows in your sheet and is 1048576. In my opinion you take the very last cell of the column and End(xlUp) won't make it better. I think Sheet1.Cells(1, "B").End(xlUp) should work better. Sorry if I'm wrong for I can't reproduce your scenario here.

Resources