So, right now I have this excel sheet where there is a last revision date. I have named this column "LastRevisionDate". And then I have a column named "RevisionFrequency" . The "RevisionFrequency" contains a drop-down menu consisting of terms, "Annually", "Bi-Annually"(2 times in a year), "Semi-Annually", and "Quarterly". And then I have a column where it states the "NextRevisionDate". So I want to create a VBA code that would calculate the NextRevisionDate from the LastRevisionDate and the RevisionFrequency.
For example. Say in column "A" i have the RevisionFrequency to be "Bi-annually" And the last revision date was Mar-14 in column "B", then I would want the NextRevisionDate in column "C" to state Mar,Sep .Thats basically saying that the item gets revised twice a year. So I would want to create a macro where Column "C" is based off the RevisionFrequency and LastRevisionDate. I realize I could do this with a formula, but I have new items being added constantly so I do not want to keep copying formulas into each cell. Also for some items, they do not need revision, I would also like to have a blank cell if there is no LastRevisionDate.
So far, I have this updated code:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim ws As Worksheet
Set ws = Sheets(1)
If Not Intersect(Target, ws.Range("LastCalDate").Value) Is Nothing Then
Dim Lastdate As Date
Dim DueDate As Variant
Dim Frequency As String
Dim R As Variant
Dim C As Variant
Dim R1 As Variant
Dim C1 As Variant
Dim R2 As Variant
Dim C2 As Variant
R = Range("LastCalDate").Row
C = Range("LastCalDate").Column
R1 = Range("CalDueDate").Row
C1 = Range("CalDueDate").Column
R2 = Range("CalFrequency").Row
C2 = Range("CalFrequency").Column
Lastdate = Cells(R, C).Value 'Last Cal Date
DueDate = Cells(R1, C1).Value 'Cal Due Date
Frequency = Cells(R2, C2)
If Frequency = "Annually" Then
DueDate = DateAdd("mmm", 12, Lastdate)
End If
If Frequency = "Semi-Annually" Then
DueDate = DateAdd("mmm", 6, Lastdate)
End If
If Frequency = "Quarterly" Then
DueDate = DateAdd("mmm", 3, Lastdate)
End If
End Sub
“Am I just overcomplicating my code?”
That is the wrong question. The first question is not “What can I do?” but “What do my users want?”
If you start by saying “I can produce wooden clogs”, you may never learn they want soft slippers. You may not be able to produce soft slippers but you can probably produce something a lot better than wooden clogs if know it is required. Start with the design of the ideal product then cut it down to what is practical.
From your description, I visualise something like this:
You may have many other columns and these three columns may be in different positions; it does not matter, we will restrict ourselves these columns for now.
It sounds to me as though you have two requirements and an issue:
You have a worksheet where the values in the Next Revision Date column may be unreliable or missing. You require a macro that will run down the existing worksheet and enter correct values into the Next Revision Date column.
You have a requirement to set the values in the Next Revision Date column automatically as new rows are added of existing Revision Frequencies and Last Revision Dates are amended. This could be achieved by running macro 1 or using the Worksheet Change event, as you suggest. There may be other approaches but I will not address this requirement.
If you look at the last three rows of my example worksheet, you will notice the day of the month in the Next Revision Date column is not the same as that in the Last Revision Date. This is because I converted the value in the Frequency column to 3, 6 or 12 and added that number of months to the Last Revision Date. In the last three rows the new month does not have as many days as the old and the VBA function has, for example, converted 30 February to 2 March. Is this the effect you require? I have included code to bring the date back to the “correct” month. Often the most difficult task in macro design is identifying all these exceptions and specifying how they are to be handled.
I will only consider macro 1 first since you can use it for both requirements while you are design and implementing macro 2. If you run into problems with macro 2, ask a new question. You can ask as many questions as you like – providing they are good questions – but they should only be one issue per question.
You need a macro that will step down every row of the worksheet. If you are using an online tutorial or you have bought a book on Excel VBA, you may find a suitable example there. If you are using neither an online tutorial nor a book, please start. It will not take long to master the basics of Excel VBA and the time spent learning the basics will quickly repay itself. Trying to search the web for code when you do not know the basics is very difficult.
If your tutorial/book does not tell you how to step down every row of the worksheet, try searching SO for “[excel-vba] find last row of worksheet”. There are lots of variations of this question so you should have no difficulty in finding something suitable. You do not have to do so on this occasion because I show you how below but I believe this is the best way of using this site. Break your requirement down into little steps and then search for a question relevant to each step.
Below is a simple macro 1. Study my code and come back with questions if necessary. However, the more you can understand on your own, the faster you will develop.
Welcome to the joys of programming.
Option Explicit
' Using constants for values that may change makes your code easier to
' understand and easier to maintain.
Const ColFrequency As Long = 1
Const ColLastRevisionDate As Long = 2
Const ColNextRevisionDate As Long = 3
Const RowDataFirst As Long = 2
Sub FixNextRevisionDate()
Dim DateLastCrnt As Date
Dim DateNextCrnt As Date
Dim NumMonthsToStep As Long
Dim RowCrnt As Long
Dim RowLast As Long
' Replace "Data" with the name of your worksheet
With Worksheets("Data")
' This is the most popular method of finding the last row but it will
' not work in every situation. I believe it is appropriate for your
' current requirement but suggest you look for questions that describe
' other methods and which explain why they might be better.
RowLast = .Cells(Rows.Count, ColFrequency).End(xlUp).Row
For RowCrnt = RowDataFirst To RowLast
' Convert Frequency to 3, 6 or 12
' I have used the LCase function to allow for inconsistent use of
' upper and lower case
Select Case LCase(.Cells(RowCrnt, ColFrequency).Value)
Case "annually"
NumMonthsToStep = 12
Case "bi-annually"
NumMonthsToStep = 6
Case "semi-annually"
NumMonthsToStep = 6
Case "quarterly"
NumMonthsToStep = 3
Case Else
' Unknown frequency. never assume the worksheet is correct
' if an error will cause your macro to fail.
' This is an easy way to highlight faulty values for user
' attention.
With .Cells(RowCrnt, ColFrequency)
.Interior.Color = RGB(255, 0, 0)
NumMonthsToStep = 0
End With
End Select
If NumMonthsToStep <> 0 Then
' Had valid frequency
If IsDate(.Cells(RowCrnt, ColLastRevisionDate).Value) Then
' Value in Last Revision Date column is a date
DateLastCrnt = .Cells(RowCrnt, ColLastRevisionDate).Value
' Calculate next date by adding NumMonthsToStep
DateNextCrnt = DateSerial(Year(DateLastCrnt), _
Month(DateLastCrnt) + NumMonthsToStep, _
Day(DateLastCrnt))
' You may not want this but it shows how to do it if you do
If Day(DateNextCrnt) < Day(DateLastCrnt) Then
DateNextCrnt = DateSerial(Year(DateNextCrnt), _
Month(DateNextCrnt), _
0)
End If
With .Cells(RowCrnt, ColNextRevisionDate)
.Value = DateNextCrnt
' Replace with date format of your choice
.NumberFormat = "d mmm yy"
End With
Else
' The Last Revision Date is not a date
With .Cells(RowCrnt, ColLastRevisionDate)
.Interior.Color = RGB(255, 0, 0)
End With
End If
End If
Next
End With
End Sub
Related
I have an Excel sheet with prices (of materials used in construction) from previous years.
I am trying to make a code that will show me all the data based on a certain year that I choose.
What my list/excel looks like
In cell E3 (in yellow), I input the year to "analyse".
I need a function that will search columns K to Q (and more since every year, prices change), for that year, and copy all the data of sales, reg. loc. and spec. loc. into the columns F, G and H.
If it's easier that, instead of putting the year in cells K3, L3 and M3 (for example), if I put it in cell N3, R3, etc. (in red) instead, the function will take the 3 previous columns and copy/paste them in columns F to H.
Option 2, if it makes the coding easier
Also the list goes until row 381, and there's a potential that more data will be input eventually so take into consideration as if the list had an infinite amount of rows. However, for the columns, it's always fixed to 3 columns.
FYI: it is not a school project. I'm trying to simplify my work instead of manually searching and copy/pasting the data every time.
Please, try the next code. It should do what (I understand) you need. It should be fast, not using clipboard for copying. As I suggested in my comment, it firstly searches/finds in the third row the year (long or string, as it is written in "E3"), starting searching after "E3", then copying the range built according to the found cell. If not a match is found, the code exits on the line If rngFirstCol Is Nothing Then Exit Sub. You may place a message there, to warn in such a case. It works on your first arrangement/picture, meaning that the year must be filled in the third row of the first column where from the necessary data should be collected/copied:
Sub ExtractPricesPerYear()
Dim sh As Worksheet, lastR As Long, rngFirstCol As Range, lngYear, necCol As Long
Set sh = ActiveSheet 'use here your necessary sheet
lngYear = sh.Range("E3").value 'the year to be searched
Set rngFirstCol = sh.rows(3).Find(What:=lngYear, After:=sh.Range("E3"), LookIn:=xlValues, Lookat:=xlWhole)
If rngFirstCol Is Nothing Then Exit Sub
necCol = rngFirstCol.Column
lastR = sh.cells(sh.rows.count, necCol).End(xlUp).row
With sh.Range(rngFirstCol.Offset(1), sh.cells(lastR, necCol + 2))
sh.Range("E4").Resize(.rows.count, .Columns.count).value = .value
End With
End Sub
Please, send some feedback after testing it.
And another issue: It is good to show us what you tried by your own. If not a piece of code, at least, something to prove that you investigated and had some ideas about the task to be solved, asking for hints, suggestions etc. proving that you know something about how it can be done...
Edited:
Following your requirement from last comment, please use the next solution. Please, copy the next code in the respective sheet code module (right click on the sheet name, then choose View Code):
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Dim lastR As Long, lastRF As Long, rngFirstCol As Range, lngYear, necCol As Long
If Target.Address(0, 0) = "E3" Then 'the code exits for any other change on the sheet
lngYear = Target.value 'the year to be searched
Set rngFirstCol = Me.rows(3).Find(What:=lngYear, After:=Me.Range("E3"), LookIn:=xlValues, Lookat:=xlWhole)
If rngFirstCol Is Nothing Then MsgBox "No such year found on the third row...:": Exit Sub
necCol = rngFirstCol.Column 'column number of the found cell
lastR = Me.cells(Me.rows.count, necCol).End(xlUp).row 'last row on the found column
lastRF = Me.Range("F" & Me.rows.count).End(xlUp).row 'last row on F:F column (to delete its content, if any)
If lastRF > 4 Then Me.Range("F4:H" & lastRF).ClearContents 'clear the range to make place for the new data
With Me.Range(rngFirstCol.Offset(1), Me.cells(lastR, necCol + 2))
Me.Range("F4").Resize(.rows.count, .Columns.count).value = .value
End With
End If
End Sub
Am trying to make a VBA validation sheet on Excel to find all the cells that do not match a predefined pattern and copy it to another sheet
My pattern is "4 numbers/5 numbers"
Ex: 1234/12345 is accepted
2062/67943 is accepted
372/13333 is not accepted
1234/1234 is not accepted etc...
I tried to put the following in the conditions sheet : <>****/***** and <>????/????? and both did not work (am not sure about the correctness of the approach as am still a beginner in VBA)
For the code itself, this is what I wrote :
Sub GuaranteeElig()
Sheets.Add After:=ActiveSheet
ActiveSheet.Name = SheetName
Sheets("MainSheet").UsedRange.AdvancedFilter Action:= _
xlFilterCopy,
CriteriaRange:=Sheets("ConditionsSheet").Range("B1:B2"), _
CopyToRange:=Range("A1"), Unique:=False
End Sub
Any tips on how I can do it ?
Thanks in advance :)
As long as the values of the numbers are independent and do not matter, and it is only the Length of the numerical strings that count, you could use a for loop on the cells from the "search" sheet (I assume this is the MainSheet as shown in your code?) where your values are contained.
From there, I'll give you a couple ways to place the data in the validation sheet (assuming this is your ConditionsSheet as shown in your code?) where you are trying to pinpoint the values.
(You may need to change part of your approach depending on how you want the incorrect set of values laid out on your secondary sheet - but this should get you started.) I added a TON of comments as you say you're new to VBA - these will help you understand what is being done.
Sub GuaranteeElig()
'Adding this to help with performance:
Application.ScreenUpdating = False
'Assuming you are adding a sheet here to work with your found criteria.
Sheets.Add After:=ActiveSheet
ActiveSheet.Name = "ConditionsSheet"
'Using the naming bits below I am assuming the data you are searching for is on MainSheet
'Get used range (most accurate and efficient way I have found yet, others on S.O.
'may have better ways for this - research it if this does not work for you)
'I have had problems using the Sheets().UsedRange method.
Dim c as Long 'This may not be necessary for you if you are looping through only column "A"
Dim r as Long
'Cells(y,x) method uses numerical values for each row (y) or column (x).
c = Cells(1, Columns.Count).End(xlToLeft).Column 'May not be necessary depending on your needs.
'Using this because you have "UsedRange" in your
'code.
'.End(xlToLeft) signifies we are going to the end of the available cell range of
'Row 1 and then performing a "Ctrl+Left Arrow" to skip all blank cells until we hit
'the first non-blank cell.
r = Cells(Rows.Count, 1).End(xlUp).Row
'.End(xlUp) method is similar - we go to the end of the available cell range for the
'column ("A" in this case), then performing a "Ctrl+Up Arrow" to skip all blank cells.
'If you have a header row which spans across the sheet, this is your best option,
'unless you have 'helper' cells which extend beyond the final column of this header
'row. I am assuming Row 1 is a header in this case - change to your needs.
'For your Rows - choose the column which contains congruent data to the bottom of
'your used range - I will assume column 1 in this case - change to suit your needs.
Dim i as long
Dim j as integer
Dim cel as Range
Dim working_Str() as String 'String Array to use later
Dim string1 as String
Dim string2 as String
Dim badString as Boolean
For i = 2 to r Step 1 'Step down from row 2 to the end of data 1 Row at a time
'Row 1 is header.
set cel=Cells(i, 1) 'Sets the cell to check - assuming data is in Column "A"
'i will change from for loop so 'cel' changes from "A2555"
'to "A2554" to "A2553" etc.
working_Str=Split(cel.Value, "/", -1) 'Splits the value based on "/" inside of cel
string1=working_Str(0) 'what we hope will always be 4 digits
string2=working_Str(1) 'what we hope will always be 5 digits
If Len(string1)<>4 Then 'string1 _(xxxx)_(/)(don't care) does not equal 4 digits in length
badString = True
Elseif Len(string2)<>5 Then ''string1 (don't care)(/)_(xxxxx)_ does not equal 5 digits in length
badString = True
End If
If badString Then 'If either strings above were not correct length, then
'We will copy cell value over to the new sheet "ConditionsSheet"
'Comment the next 2 commands to change from going to one row at a time to
'Matching same row/Cell on the 2nd sheet. Change to suit your needs.
j = j + 1 'Counter to move through the cells as you go, only moving one cell
'at a time as you find incorrect values.
Sheets("ConditionsSheet").Range("A" & j).Value=cel.Value 'sets the value on other sheet
'UNComment the next command to change from going to one row at a time to
'matching same row/cell on the 2nd sheet. Change to suit your needs.
'Sheets("ConditionsSheet").Range("A" & i).Value=cel.Value
End if
badString = False 'resets your boolean so it will not fail next check if strings are correct
Next i
'Returning ScreenUpdating back to True to prevent Excel from suppressing screen updates
Application.ScreenUpdating = True
End Sub
UPDATE
Check the beginning and ending lines I just added into the subroutine. Application.ScreenUpdating will suppress or show the changes as they happen - suppressing them makes it go MUCH quicker. You also do not want to leave this setting disabled, as it will prevent Excel from showing updates as you try to work in the cell (like editing cell values, scrolling etc. . . Learned the hard way. . .)
Also, if you have a lot of records in the given row, you could try putting the data into an array first. There is a great example here at this StackOverflow Article.
Accessing the values of a range across multiple rows takes a LOT of bandwidth, so porting the range into an Array first will make this go much quicker, but it still may take a bit. Additionally, how you access the array information will be a little different, but it'll make sense as you research it a little more.
Alternative To VBA
If you want to try using a formula instead, you can use this - just modify for the range you are looking to search. This will potentially take longer depending on processing speed. I am entering the formula on 'Sheet2' and accessing 'Sheet1'
=IF(COUNTIF(Sheet1!A1,"????/?????"),1,0)
You are spot on with the search pattern you want to use, you just need to use a function which uses wildcard characters within an "if" function. What you do with the "If value is true" vs "If value is false" bits are up to you. COUNTIF will parse wildcards, so if it is able to "count" the cell matching this string combination, it will result in a "True" value for your if statement.
Regex method, this will dump the mismatched value in a worksheet named Result, change the input range and worksheet name accordingly.
In my testing, 72k cells in UsedRange takes about 4seconds~:
Option Explicit
Sub GuaranteeElig()
Const outputSheetName As String = "Result"
Dim testValues As Variant
testValues = ThisWorkbook.Worksheets("MainSheet").UsedRange.Value 'Input Range, change accordingly
Const numPattern As String = "[\d]{4}\/[\d]{5}"
Dim regex As Object
Set regex = CreateObject("VBScript.Regexp")
regex.Pattern = numPattern
Dim i As Long
Dim n As Long
Dim failValues As Collection
Set failValues = New Collection
'Loop through all the values and test if it fits the regex pattern - 4 digits + / + 5 digits
'Add the value to failValues collection if it fails the test.
For i = LBound(testValues, 1) To UBound(testValues, 1)
For n = LBound(testValues, 2) To UBound(testValues, 2)
If Not regex.Test(testValues(i, n)) Then failValues.Add testValues(i, n)
Next n
Next i
Erase testValues
Set regex = Nothing
If failValues.Count <> 0 Then
'If there are mismatched value(s) found
'Tranfer the values to an array for easy output later
Dim outputArr() As String
ReDim outputArr(1 To failValues.Count, 1 To 1) As String
For i = 1 To failValues.Count
outputArr(i, 1) = failValues(i)
Next i
'Test if output worksheet exist
Dim outputWS As Worksheet
On Error Resume Next
Set outputWS = ThisWorkbook.Worksheets(outputSheetName)
On Error GoTo 0
'If output worksheet doesn't exist, create a new sheet else clear the first column for array dump
If outputWS Is Nothing Then
Set outputWS = ThisWorkbook.Worksheets.Add
outputWS.Name = outputSheetName
Else
outputWS.Columns(1).Clear
End If
'Dump the array starting from cell A1
outputWS.Cells(1, 1).Resize(UBound(outputArr, 1)).Value = outputArr
Else
MsgBox "No mismatched value found in range"
End If
Set failValues = Nothing
End Sub
If you do not need duplicate values in the list of mismatched (i.e. unique values) then sound out in the comment.
I am currently working on a warehouse datasheet and looking to capture information from it. I need help with either a formula or VBA code.
A B C
Row 1 - product - batch number - expiry date
These are 3 columns from multiple within the sheet, however, the focus is on them. I am trying to find a formula or VBA code to allow me to do the following:
The word "cake" used as a product reference.
If a cell within the product column has the value "cake", return the value of the cell from the expiry date column which is on the same row as the initial cell found.
Repeat this process, but skip the previously found cell.
Currently, I tried this formula:
=IF(A:A="Cake",C1,"")
This is what I started with and don't have a clue after it. Whatever I search for in Google I can't adjust it to what I want. I tried Vlookup too.
To me this seems like I need a VBA code that can do that on a loop and return the values automatically for me.
I know my attempt is pathetic, but I've been searching online for 2 days with no progress. Can you suggest something? Thank you
I am expecting to have a separate sheet, from all the input sheets, collecting a list of products, their batch number and the expiry date related to them, to apply conditional formatting to be warned if a batch is due to be expired.
This would be relatively easy to do in VBA:
Sub returnExpirydates()
Dim strInput As String
Dim lngCount As Long, lngRow As Long
Dim wsInput As Worksheet, wsOutput As Worksheet
strInput = InputBox("Please enter the desired product.")
lngCount = 2
lngRow = 2
Set wsInput = Sheets("YourInputSheetName")
Set wsOutput = Sheets("YourOutputSheetName")
wsOutput.Cells.Clear
wsOutput.Rows(1).Value = wsInput.Rows(1).Value
Do While wsInput.Cells(lngCount, 1).Value <> ""
If Cells(lngCount, 1).Value = strInput Then
wsOutput.Rows(lngRow).Value = wsInput.Rows(lngCount).Value
lngRow = lngRow + 1
End If
lngCount = lngCount + 1
Loop
End Sub
This might require a few tweaks to fit your file, let me know if you have follow-up questions.
Say that I have a spreadsheet that allows users to put in some metadata like the following:
Date range start: mm/dd/yyyy
Date range end: mm/dd/yyyy
Mondays: (y/n)
Tuesdays: (y/n)
Wednesdays: (y/n)
Thursdays: (y/n)
Fridays: (y/n)
Based on that, I want to generate a list of dates in the format of mm/dd/yyyy that starts on 4/1/2019, ends on 4/30/2019 and only includes dates of the day that was indicated with a y.
So if a user put in start date = 04/01/2019, end date = 04/30/2019, y for just Mondays and Wednesdays, the list would look like:
04/01/2019
04/03/2019
04/08/2019
04/10/2019
04/15/2019
04/17/2019
04/22/2019
04/24/2019
04/29/2019
Couldn't find an Excel function to start with. I don't know VBA but imagine it would be possible to do this with that.
If I wanted to write this in Python by using an add-in like Pyxll, would everyone with a copy of the Excel file be required to install Pyxll?
#simplycoding: VBA doesn't have a function or suroutine ready to do what you are looking for right out of the box. However, you can compose your own ones based on whatever VBA has on offer, which is a lot.
This is my startup scenario:
I wrote, tested and commented the following SUB in some 20 minutes. Believe me when I say I'm not a first row VBA coder.
Sub DateList()
'(C) Antonio Rodulfo, 2019
Dim dEnd, dStart, dCounter As Date
Dim iaDays(1 To 5) As Integer
Dim iCounter, iRow As Integer
' Indent your sentences properly
' Reading parameters
dStart = Cells(2, 1).Value
dEnd = Cells(2, 2)
For iCounter = 1 To 5
If Cells(2, 2 + iCounter) = "y" Then
iaDays(iCounter) = 1
Else
iaDays(iCounter) = 0
End If
Next iCounter
' Here's where the list of dates will start
iRow = 4
' I process the dates: Excel stores dates in its own
' coding, which we can use to run a for..next loop
For dCounter = dStart To dEnd
' Weekday(datecode,type) returns the day of week
' type 2 means the week starts with monday being day 1
iCounter = Weekday(dCounter, 2)
' The sub only sets dates for working days
' monday to friday
If iCounter <= 5 Then
' date must be set if found "y" in the matching day
If iaDays(iCounter) = 1 Then
' I like setting the proper numberformat so
' that no surprises are found when reading it
Cells(iRow, 1).NumberFormat = "dd/mmm/yyyy"
Cells(iRow, 1) = dCounter
' Increasing iRow sets the focus on next row
iRow = iRow + 1
End If
End If
' Adding the index name to the next sentence helps
' tracking the structures
Next dCounter
End Sub
I always recommend using Option Explicit when coding. It can seem annoying at first, but it will help you a lot when testing and debugging your code.
Good luck!
I was challenged by your request to not use VBA at all, so I was playing around with some Excel functions and here's what I would like you to try.
I used your metadata in the following cells:
OPTION 1 - easy
Enter the following Array function into cell D1 (Ctrl+Shift+Enter) and drag it all the way to the right (e.g. up to cell AW1):
=IF(AND(ISNUMBER(MATCH(WEEKDAY($B$1+COLUMN()-4,2),--($B$3:$B$7="y")*(ROW($B$3:$B$7)-2),0)),($B$1+COLUMN()-4)<=$B$2),$B$1+COLUMN()-4,"")
All dates that are between Start & End dates and for the required weekdays are displayed. However, this option does not prevent the gaps, so you will have lots of blank columns in between.
OPTION 2 - complete
Enter the following Array function into cell D2 (Ctrl+Shift+Enter) and drag it all the way to the right:
=IFERROR(SUMPRODUCT(SMALL(($B$1+ROW($B$1:$B$30)-1)*(IF(ISNUMBER(MATCH(WEEKDAY($B$1+ROW($B$1:$B$30)-1,2),(--($B$3:$B$7="y")*(ROW($B$3:$B$7)-2)),0)),1,0)),30-COUNT(MATCH(WEEKDAY($B$1+ROW($B$1:$B$30)-1,2),(--($B$3:$B$7="y")*(ROW($B$3:$B$7)-2)),0))+COLUMN()-3)),"")
As you can see, this option displays all "proper" dates next to each other, without any gaps.
Hope you will find this helpful - I had lots of fun playing around with the second option and I'm sure it can be still improved.
Take care,
Justyna
in my job I have very often to create prefixes. Since last week I think that I can do faster my job with a Macro in excel, but I never have developed in VBA before and need your help.
We get a list with article numbers from any supplier and then I have to create the prefixes for our System. Our System is looking for the prefix and then it knows the supplier. If the first 6 chars are exactly the same with another supplier, so the prefixes from both supplier is getting longer to 7 chars. If it's the same again, the prefix is getting an eight char and so on.
Example:
article numbers from supplier_1:
04012384724993
04012384473373
04012384111453
...
article numbers from supplier_2:
12345671846219
12345629946120
12345629815294
...
article numbers from supplier_3:
12345694724109
12345694715268
12345694724773
...
Now you see that first chars from each supplier are the same.
For Supplier_1 all numbers beginning with "040123", so that's the first prefix.
Supplier_2 ans 3 have the same first 6 chars, so here we use one more to identificate him.
Supp_2 -> "1234567" and "1234562"
Supp_3 -> "1234569"
Supplier_2 have now 2 prefixes, because the 7th position is different in some article numbers, but not the same like supplier_3 is using at this position.
Now I have an excel sheet with column A and B.
In column A I paste all article numbers from supplier_1 and in column B I paste these from supplier_2.
Now I want to run a macro, that create a variable "search" with the first 6 chars from Cell A1 and check it against Column B. If one of the numbers in Column B is the same then variable "search" get additional the next char from Cell A1 and check again. If now the first 7 chars couldn't be found in Column B, it's the first prefix from supplier_1. I want to paste it into column D.
Now the variale "search" get the first 6 chars from the next Cell in column A, (A2), later A3, ... and check it against Column B.
I don't know, how to get the first 6 chars into the variable "search".
Can someone help me please?
Thank you very much.
It is always a good idea to approach big problems in as small chunks as possible. Indeed, it may be a good start to assign the first few characters of a string to a variable. A quick Google search would most likely point you to the Left function. Here's a link to the MSDN page for more information on how it works and how to use it.
I also suggest that you enable the Immediate Window, which can be done with Ctrl + G by default. Using Debug.Print will be one of your strongest tools while writing new code.
Sub Example1()
Dim searchRange As Range
Dim search As String
Set searchRange = ThisWorkbook.Worksheets("Sheet1").Range("A1")
search = Left(searchRange.Value, 6)
Debug.Print search
End Sub
Here's a snippet to give you an idea of how you might go about solving the next step of the problem.
Sub Example2()
Dim compareRange As Range
Dim cell As Range
' SpecialCells is one of many ways to find all populated cells
Set compareRange = ThisWorkbook.Worksheets("Sheet1").Columns(2) _
.SpecialCells(xlCellTypeConstants)
For Each cell In compareRange
Debug.Print cell.Value
Next
End Sub
Please remember that StackOverflow is here to help with specific coding problems that you can't get over with the resources you can find online.
I had some difficulty deciphering exactly what you needed but here is what I have come up with.
I am going to assume that you know how to insert a module into your excel spreadsheet, copy code, and run a macro. If you do not know how please let me know and I will try to assist further.
If this is not what you need please provide me with a sample data set and the answers that you would like to get from the macro so that I can compare as I develop. Best of luck with your projects!
VBA module code
'This subroutine will take the contents of column A cells and search column B for matching digits
' if they are not found it will copy the current search term into column D
Option Explicit
Sub searchPrefix()
Dim cellContents As String
Dim tempSearchVariable As String
Dim isFound As Boolean
Dim quantitySearchCharacters As Integer
Dim entryCounter As Integer
Dim i As Integer
isFound = False
quantitySearchCharacters = 6
entryCounter = 0
'counts number of entries in column A
Cells.Range("A1").Select
Do Until IsEmpty(ActiveCell)
entryCounter = entryCounter + 1
ActiveCell.Offset(1, 0).Select
Loop
' gets value of comparison cell in column A
For i = 0 To entryCounter - 1
cellContents = Cells(1 + i, 1).Value
tempSearchVariable = Left(cellContents, quantitySearchCharacters)
Cells.Range("B1").Select
Do Until IsEmpty(ActiveCell)
' detects if B1 column cell content matches the current search terms and then adds more characters if required
If Left(ActiveCell.Value, quantitySearchCharacters) = tempSearchVariable Then
quantitySearchCharacters = quantitySearchCharacters + 1
tempSearchVariable = Left(cellContents, quantitySearchCharacters)
isFound = True
End If
If isFound Then
isFound = False 'reset flag
Cells.Range("B1").Select
Else
ActiveCell.Offset(1, 0).Select
End If
Loop
Cells(1 + i, 4).Value = tempSearchVariable ' prints the discovered unique prefix to column D
Next i
End Sub