1

I wrote some code but its not completed because of my expertise in VBA. I have file consisting of 2 sheets. Sheet1 is current inventory and Sheet2 has orders.

Sheet2

[![enter image description here][1]][1]

Sheet1

[![enter image description here][2]][2]

I am looking for a help to complete the code. I just want that Code will pick up the Sheet2 Col"A" SKU's and will match that in Sheet1 Col"A" SKU's if same SKU's match.

Then

Code will search the nearest expiry date in Sheet1 Col"G" for those SKU's which have been matched and will copy the same row for those SKU's which expiry is going to end soon. After that Paste that data into "NewSheet" (The purpose of Expiry date is to sale those product which expiry is about to end so that we may not face the loss)

I have highlighted the Sheet1 Data with nearest expiry. your help will be much appreciated

MyCode.

    Sub Copypaste()

    Dim srchtrm As String
    Dim rng As Range, destRow As Long
    Dim shtSrc As Worksheet, shtDest As Worksheet
    Dim c As Range
    Dim i As Integer
    Dim Today As Date
    
    Set shtSrc = Sheet1
    Set shtDest = Sheet2
    destRow = 2
    Sheets.Add.Name = "NewSheet"

    Set rng = Application.Intersect(shtSrc.Range("A:A"), shtSrc.UsedRange)

    For Each c In rng.Cells
        If c.Value = Sheet1.Range("A2") Then
            
            c.EntireRow.Copy Sheets("NewSheet").Cells(destRow, 1)
          
            destRow = destRow + 1

        End If
    Next
    
End Sub

Code result in "New Sheet" [![enter image description here][3]][3]

Sheet Link https://drive.google.com/file/d/1yB1lsqm7K8Vk9EJMWRPHm05RDwTxVeKC/view?usp=sharing [1]: https://i.stack.imgur.com/v36cc.png [2]: https://i.stack.imgur.com/FVu2q.png [3]: https://i.stack.imgur.com/s6ygA.png

  • Hi @mento what does end soon mean in `copy the same row for those SKU's which expiry is going to end soon`? You just want the earliest sheet 1 row per sku? so basically yuo want to end up with a list of the earliest inventory date for all skus for which you have an order? – JohnnieL Feb 08 '21 at 16:07
  • Hello, @JohnnieL That means there are repeated skus in sheet1 so code will pick those skus which expiry is near i have highlighted them in Sheet1 picture. Yes you are right. –  Feb 08 '21 at 16:12
  • Where exactly are you stuck? You could use MINIF to identify the nearest date. – SJR Feb 08 '21 at 16:48
  • Hi, @SJR i am stuck in multiple things 1st is how to go for the Sheet2 second sku then 3rd and so on. then loop for Expiry date to get the required result. –  Feb 08 '21 at 16:52

3 Answers3

1

It seems to be solved by using sql.

Sub test()
    Dim Ws As Worksheet
    Dim strSQL As String, strU As String
    Dim sName(1 To 2) As Variant
    Dim i As Integer
    
    Set Ws = Sheets(3)

    For i = 1 To 2
        sName(i) = Sheets(i).Name
    Next i
        
    strSQL = "SELECT d.*  "
    strSQL = strSQL & " FROM [" & sName(2) & "$] as a left join "
    
    strSQL = strSQL & " ( select b.* FROM [" & sName(1) & "$] as b right join "
    strSQL = strSQL & "    ( select sku, min([Expiry Date]) as sday from [" & sName(1) & "$] group by sku) as c "
    strSQL = strSQL & " on b.sku = c.sku and  b.[Expiry Date]=c.sday) as d "
    
    strSQL = strSQL & "on a.sku = d.sku "
        
    exeSQL Ws, strSQL
    
    
End Sub

Sub exeSQL(Ws As Worksheet, strSQL As String)

    Dim Rs As Object  'ADODB.Recordset
    Dim strConn As String
    Dim i As Integer

    strConn = "Provider=Microsoft.ACE.OLEDB.12.0;" & _
        "Data Source=" & ThisWorkbook.FullName & ";" & _
            "Extended Properties=Excel 12.0;"
    
    Set Rs = CreateObject("ADODB.Recordset") 'New ADODB.Recordset
    
    Rs.Open strSQL, strConn
    
    If Not Rs.EOF Then
         With Ws
            .Range("a2").CurrentRegion.ClearContents
            For i = 0 To Rs.Fields.Count - 1
               .Cells(1, i + 1).Value = Rs.Fields(i).Name
            Next
            .Range("a2").CopyFromRecordset Rs
            .Columns.AutoFit
        End With
    End If
    Rs.Close
    Set Rs = Nothing
End Sub
Dy.Lee
  • 7,527
  • 1
  • 12
  • 14
  • I really do not know how to use it with Sql. @Dy.Lee –  Feb 09 '21 at 16:10
  • @dy.lee totally agree - in thinking about what is trying to be achieved here, intellectually this is closest to an sql query – JohnnieL Feb 09 '21 at 16:32
0

i think this works.

Logic

  1. Make an array of all skus in sheet 2 (orders)
  2. Filter all stock lines (sheet 1) for those skus
  3. Copy all stock lines to new sheet
  4. remove all but earliest line for each stock line

This is all quite "neat" until the "brute force" removal in step 4 - let me know if it works and if there are any suggestions out there for how 4th step could be achieved more elegantly I'd love to hear about that

Option Explicit

Sub Copypaste()

    Dim destRow As Long
    Dim shtSrc As Worksheet, shtDest As Worksheet
    Dim i As Integer
    
    Set shtSrc = ThisWorkbook.Sheets("sheet1")
    Set shtDest = ThisWorkbook.Sheets("sheet2")
    destRow = 2
    
    'Step 1: identify order skus
    Dim order_skus As Range
    Set order_skus = shtDest.Range(shtDest.Range("a" & destRow), shtDest.Range("a" & shtDest.Rows.Count).End(xlUp))
    
    Dim arr() As Variant
    ReDim arr(order_skus.Rows.Count - 1)
    i = 0
    Dim r As Range
    For Each r In order_skus
      arr(i) = CStr(r.Value)
      i = i + 1
    Next r
    
    ' step 2: filter lines for skus we have orders
    shtSrc.UsedRange.AutoFilter
    shtSrc.UsedRange.AutoFilter field:=1, Criteria1:=arr, Operator:=xlFilterValues
    
    Dim ws_out As Worksheet
    Set ws_out = Sheets.Add
    ws_out.Name = "NewSheet"
    
    'step 3: copy filtered values
    shtSrc.UsedRange.SpecialCells(xlCellTypeVisible).Copy Destination:=ws_out.Range("a1")
    'remove auto filter
    shtSrc.UsedRange.AutoFilter
    
    'step 4: sort by sku and date and remove not first values for each sku
    ws_out.Range("a1").CurrentRegion.Sort key1:=ws_out.Range("a1"), order1:=xlAscending, Header:=xlYes, key2:=ws_out.Range("g1"), order2:=xlAscending
    Set r = ws_out.Range("a1")
    i = 1
    While Not IsEmpty(r.Offset(i, 0).Value)
      ' if this row sku same as previous
      If r.Offset(i, 0).Value = r.Offset(i - 1, 0).Value Then
        'remove the not-first row
        r.Offset(i, 0).EntireRow.Delete
      Else
        ' move to next item to check
        i = i + 1
      End If
    Wend
    
End Sub

JohnnieL
  • 1,192
  • 1
  • 9
  • 15
  • You are great @JohnnieL thank you very very much. Just one more favor that when i run the code again it gives me an error that sheet already exists. Is there anyway if "NewSheet" already exists then i run the code even 100 times then nothing should be happen. Like Exist Sub –  Feb 08 '21 at 17:49
  • I'll let you figure this out but there is no "worksheet exists" function - you'll find that question in stack overflow for sure but in short you need to access the sheet you want to test but supress errors while you do it so code doesnt break so something like `dim r as range/set r=nothing/on error then resume/set r=worksheets("NewSheet")/on error then goto 0/if not r is nothing then / sheet exists/endif ` – JohnnieL Feb 08 '21 at 17:54
  • Ok @JohnnieL thank you so much for helping out. –  Feb 08 '21 at 17:56
  • sorry to bother you @JohnnieL i need your help with one more step that if the Inventory Sheet nearest expiry sku quantity is 0 then it populate the 0 in new sheet. I just want that if it founds the nearest expiry quantity 0 then it should go to other nearest expiry for same sku. I would appreciate your help. –  Feb 08 '21 at 19:57
  • Can you please have look into this @JohnnieL –  Feb 09 '21 at 16:17
  • hi - just filter those out of the initial selection, so add a second criterion to this line `shtSrc.UsedRange.AutoFilter field:=1, Criteria1:=arr, Operator:=xlFilterValues` to exclude zero quantities ... – JohnnieL Feb 09 '21 at 16:25
  • https://stackoverflow.com/questions/28575754/filter-out-multiple-criteria-using-excel-vba/28579593 – JohnnieL Feb 09 '21 at 16:26
  • Yes i have find out the relevant way to do this but always had an error. That's why requested you to please add this last line. @JohnnieL –  Feb 09 '21 at 16:29
  • 1
    Hi busy on other things at the moment but try changing this line: `If r.Offset(i, 0).Value = r.Offset(i - 1, 0).Value or r.Offset(i , 2).Value = 0Then` – JohnnieL Feb 09 '21 at 16:42
  • 1
    basically delete the line if we have already seen the sku or the quantity is zero – JohnnieL Feb 09 '21 at 16:43
  • Sure I will try and let you know the result thank you. @JohnnieL –  Feb 09 '21 at 16:46
  • I have tried it as you said but it loads the all data except which quantity is 0 i would request please edit the question if possible. I can wait. @JohnnieL –  Feb 09 '21 at 17:03
  • @Mento see new answer - i put it separate to add in clearly the changed requirements – JohnnieL Feb 09 '21 at 17:35
0

Implementing new requirements

  1. Clear "NewSheet" if it already exists
  2. Exclude row where quantity = 0
Option Explicit

Sub Copypaste()

    Dim destRow As Long
    Dim shtSrc As Worksheet, shtDest As Worksheet
    Dim i As Integer
    
    Set shtSrc = ThisWorkbook.Sheets("sheet1")
    Set shtDest = ThisWorkbook.Sheets("sheet2")
    destRow = 2
    
    'Step 1: identify order skus
    Dim order_skus As Range
    Set order_skus = shtDest.Range(shtDest.Range("a" & destRow), shtDest.Range("a" & shtDest.Rows.Count).End(xlUp))
    
    Dim arr() As Variant
    ReDim arr(order_skus.Rows.Count - 1)
    i = 0
    Dim r As Range
    For Each r In order_skus
      arr(i) = CStr(r.Value)
      i = i + 1
    Next r
    
    ' step 2: filter lines for skus we have orders
    shtSrc.UsedRange.AutoFilter
    shtSrc.UsedRange.AutoFilter field:=1, Criteria1:=arr, Operator:=xlFilterValues
    
    ' test if sheet exists, create if not and clear if it does
    Dim ws_out As Worksheet
    Set ws_out = Nothing
    On Error Resume Next
    Set ws_out = Worksheets("NewSheet")
    On Error GoTo 0
    
    If ws_out Is Nothing Then
      Set ws_out = Sheets.Add
      ws_out.Name = "NewSheet"
    Else
      ws_out.Cells.Clear
    End If
    
    
    'step 3: copy filtered values
    shtSrc.UsedRange.SpecialCells(xlCellTypeVisible).Copy Destination:=ws_out.Range("a1")
    'remove auto filter
    shtSrc.UsedRange.AutoFilter
    
    'step 4: sort by sku and date and remove not first values for each sku
    ws_out.Range("a1").CurrentRegion.Sort key1:=ws_out.Range("a1"), order1:=xlAscending, Header:=xlYes, key2:=ws_out.Range("g1"), order2:=xlAscending
    Set r = ws_out.Range("a1")
    i = 1
    While Not IsEmpty(r.Offset(i, 0).Value)
      ' if this row sku same as previous
' delete row if already know sku OR qty is zero
      If r.Offset(i, 0).Value = r.Offset(i - 1, 0).Value Or r.Offset(i, 2).Value = 0 Then
        'remove the not-first row
        r.Offset(i, 0).EntireRow.Delete
      Else
        ' move to next item to check
        i = i + 1
      End If
    Wend
    
End Sub
JohnnieL
  • 1,192
  • 1
  • 9
  • 15
  • Its working same i said recently that it loads all the data except which quantity is 0. with error OBJECT REQUIRED on this line "While Not IsEmpty(r.Offset(i, 0).Value)" @JohnnieL –  Feb 09 '21 at 17:59
  • hi @Mento sorry i dont understand that, some questions to clarify: 1. You want to include zero or not? 2.what line gives `object required` and waht row is being processed 3. can you paste the failing data and output at that point thanks – JohnnieL Feb 09 '21 at 18:02
  • 1
    Can i add sample sheet @JohnnieL as google sheet in question. –  Feb 09 '21 at 18:03
  • 1. No if the quantity is Zero then skip and go the same sku which has quantity. 2 here is the error https://ibb.co/0Bt2Lc1 Sure. –  Feb 09 '21 at 18:07
  • 1
    that error relates to a different question? - that error is dealt with at the end of the answer to that question – JohnnieL Feb 09 '21 at 18:09
  • I have uploaded a sample sheet Where if you run your first code it will load the skus available in sheet "Order" with minimum expiry date. If you run your second code it will loads all data except with 0 quantity.. Your first code is accurate but needs to skip skus which has 0 quantity –  Feb 09 '21 at 18:13
  • 1
    ok have fixed `Set r = ws_out.Range("a1") i = 1` is correct `Set r = ws_out.Range("a2") i = 0` is a bug for case when first row is zero qty – JohnnieL Feb 09 '21 at 18:17
  • Thank you very very much for this consistent help @JohnnieL you are truly a helper. –  Feb 09 '21 at 18:19
  • 1
    You're welcome - but i have to get to the day job now :o) – JohnnieL Feb 09 '21 at 18:19
  • Haha @JohnnieL i am sorry that i tool your much time –  Feb 09 '21 at 18:24