1

I am a beginner in VBA.

I have two workbooks, one containing Demand and the other Storage (or Supply).

The demand workbook is ordered by date - from the earliest to the latest.

In the storage workbook I have quantities of each tool to each Machine.

I want to create a subroutine that deletes the earliest first rows in the demand workbook for each tool in the storage workbook. For example, if in storage I have 3 tools of type Aleris, I want to delete the earliest 3 rows in demand that include Aleris.

Here are examples of the workbooks:

Demand: Demand Workbook

Storage:

Storage Workbook

Here is the code I've started, but I'm stuck. If someone can advise me with ideas on how to proceed, or help me with the code I'll be glad.

Option Explicit

Sub Demand_Minus_Storage()
Dim QT As Integer
Dim i As Integer

Dim Demand_WB As Workbook
Set Demand_WB = Workbooks.Open("C:\Users\rosipov\Desktop\eliran\MFG - GSS\Demand_Optics " & Format(Now(), "dd.mm.yyyy") & ".xlsx")

Dim storage_wb As Workbook
Set storage_wb = Workbooks.Open("C:\Users\rosipov\Desktop\eliran\MFG - GSS\OpticLabStorage.xlsm")


storage_wb.Worksheets("Illuminator").Range("C3").Activate
Set QT = ActiveCell.Value
Demand_WB.Worksheets("Illuminators").Activate



End Sub
robinCTS
  • 5,746
  • 14
  • 30
  • 37
Rafael Osipov
  • 720
  • 3
  • 18
  • 40
  • 1
    Side note: I recommend to [always use `Long` instead of `Integer`](https://stackoverflow.com/a/26409520/3219613) there is no advantage in using `Integer` but you can run into several issues if you do. – Pᴇʜ Sep 11 '17 at 07:44

3 Answers3

2

The beginning is very good :)

Option Explicit

Sub Demand_Minus_Storage()
Dim QT As Long
Dim i As Long
Dim j As Long
Dim lastRow As Long
Dim lastRowDemands As Long
Dim toolName As String

Dim demand_wb As Workbook
Set demand_wb = Workbooks.Open("C:\Users\rosipov\Desktop\eliran\MFG - GSS\Demand_Optics " & Format(Now(), "dd.mm.yyyy") & ".xlsx")

Dim storage_wb As Workbook
Set storage_wb = Workbooks.Open("C:\Users\rosipov\Desktop\eliran\MFG - GSS\OpticLabStorage.xlsm")

'in storage workbook, determine how many rows we have
'I assume that sheets in workbooks you mentioned are first ones!
'generally, use storage_wb.Worksheets("name of the sheet")...
lastRow = storage_wb.Worksheets(1).Cells(2, 1).End(xlDown).Row

'get also last row of table in demands_wb
lastRowDemands = demands_wb.Worksheets(1).Cells(2, 1).End(xlDown).Row

For i = 3 To lastRow
    QT = storage_wb.Worksheets(1).Cells(i, 3).Value 'get QT of tool
    toolName = LCase(storage_wb.Worksheets(1).Cells(i, 1).Value) 'get name of tool, all characters are lowered, in order to better comparison

    'loop through demands table
    For j = 1 To lastRowDemands
        'if tool name is found in E column, delete that row
        If InStr(1, LCase(demands_wb.Worksheets(1).Cells(5, j).Value), toolName) > 0 Then
            demands_wb.Worksheets(1).Rows(j).Delete
            'we have to subtract one from j, so we don't omit any row
            j = j - 1
            'we also have one row less to check
            lastRowDemands = lastRowDemands - 1
            QT = QT - 1 
        End If
        If QT = 0 Then
            'if we deleted the desired amount, then exit loop
            Exit For
        End If
    Next j
Next i
End Sub
Michał Turczyn
  • 32,028
  • 14
  • 47
  • 69
  • 1
    Side note: (1) I recommend to [always use `Long` instead of `Integer`](https://stackoverflow.com/a/26409520/3219613) especially when using it for iterating rows. Excel has more rows than `Integer` can handle. (2) `lastRow` is not declared it will fail on `Option Explicit` – Pᴇʜ Sep 11 '17 at 07:49
  • I also recommend using `Worksheets(1)` instead of `Sheets(1)` because the `Sheets` collection also contains charts etc. but if sheet 1 is a chart then `Sheets(1).Cells` will fail. `Worksheets` only contains worksheets. In most cases when people use `Sheets` they really meant to use `Worksheets`. I know these are only small differences but they can make your code safe or not. – Pᴇʜ Sep 11 '17 at 07:53
  • Sorry that I bother you again. But this is just another suggestion that makes your code easier: If you run your loop backwards `For j = lastRowDemands To 1 Step -1` then you don't need to correct the counter `j` for not omitting rows by deletion. This trick works because deleting rows only affect rows *AFTER* the deleted row but you walk backwards so it doesn't affect your counter. – Pᴇʜ Sep 11 '17 at 08:01
  • 1
    I'm aware of that, but OP said that he needs to delete first three found rows :) – Michał Turczyn Sep 11 '17 at 08:02
  • Hi, thanks for helping. the code isn't deleting nothing but the top row. in the demand there are few types of machins. Just the first worf is "Aleris",and then there is Aleris "8350" or something. – Rafael Osipov Sep 11 '17 at 08:02
  • @MichałTurczyn Ah my fault didn't have that in mind anymore. You are right. – Pᴇʜ Sep 11 '17 at 08:04
  • I used manual search to check it with ctrl F and when I search for "Aleris" for example, and Excel doesn't finds it somehow. @MichałTurczyn – Rafael Osipov Sep 11 '17 at 08:18
  • I added small change, try now. – Michał Turczyn Sep 11 '17 at 08:20
  • Hi @MichałTurczyn it still deletes only top row. maybe beacuse it is searching for a specific word and not a part of text inside the cell. – Rafael Osipov Sep 11 '17 at 09:49
  • If you analyzed the code, you'd find `InStr` function, which searches for a substring. So that's not the case, but good start to investigation - you should investigate code for yourself, I included descriptions, so you can experiment a bit. I don't have your data, so I can't execute any test and look for bugs. I already created (almost) whole code for you and hopefully you will be able to adjust it. – Michał Turczyn Sep 11 '17 at 10:22
  • @RafaelOsipov I added again some changes, try again :) – Michał Turczyn Sep 11 '17 at 10:53
  • @MichałTurczyn Now it deleted first two rows. I want to delete number QT of first rows of "Aleris" – Rafael Osipov Sep 11 '17 at 12:31
1

First sort your data by date. Then run a For loop and check the value against QT.

Public Sub DeleteFromDemand()

Dim storageRng As Range
Dim demandRng As Range
Dim loopCellStorage As Range
Dim loopcell As Range
Dim cntToDelete As Integer
Dim alreadyDeleted As Integer
'comment make a storage range name.
Set demandRng = Range("DemandRng")
Set storageRng = Range("StorageRng")

For Each loopCellStorage In storageRng.Columns(1).Rows.Cells

For Each loopcell In demandRng.Columns(5).Rows.Cells

    If loopcell.Value Like "*" & loopCellStorage.Value2 & "*" Then
       If alreadyDeleted <= loopCellStorage.Columns(3).Value2 Then
           alreadyDeleted = alreadyDeleted + 1
           loopcell.EntireRow.Delete xlShiftUp
       Else
         Exit For
       End If
    End If
Next loopcell
Next 
End Sub

Try this.

  1. Create named ranges for demand and storage data.
  2. Loop through the storage cells for value to match and the count. (first For loop)
  3. Loop through the demand cells for the column to match and if found note the count to values to be deleted.If this also is true then delete the row else exit. (second for loop)
  4. The alreadyDeleted variable keeps a count of rows that are deleted.
Canute
  • 69
  • 6
1

This should work exactly as is against your own workbooks, as I've left your code untouched except for Integer -> Long and commenting out the unnecessary lines. (It works fine using my test worksheets.)

Note that it only uses one loop! The inner loop is replaced with filtering and sorting

Sub Demand_Minus_Storage()
  'Dim QT As Long
  'Dim i As Long

  Dim Demand_WB As Workbook
  Set Demand_WB = Workbooks.Open("C:\Users\rosipov\Desktop\eliran\MFG - GSS\Demand_Optics " & Format(Now(), "dd.mm.yyyy") & ".xlsx")

  Dim storage_wb As Workbook
  Set storage_wb = Workbooks.Open("C:\Users\rosipov\Desktop\eliran\MFG - GSS\OpticLabStorage.xlsm")

  'storage_wb.Worksheets("Illuminator").Range("C3").Activate
  'QT = ActiveCell.Value
  Demand_WB.Worksheets("Illuminators").Activate

  Dim rngRow As Range
  With storage_wb.Worksheets("Illuminator")
    For Each rngRow In .Range(.Rows(3), .Rows(WorksheetFunction.Match("*", .Range("A:A"), -1))).Rows
      With Demand_WB.Worksheets("Illuminators").UsedRange.Offset(1)
        .Sort .Columns(5) ' Tool Type
        .Offset(-1).AutoFilter Field:=5, Criteria1:="=" & rngRow.Cells(1) & "*"
        .Sort .Columns(2) ' Due Date
        With .SpecialCells(xlCellTypeVisible).EntireRow.Areas(1)
          Range(.Rows(1), .Rows(WorksheetFunction.Min(rngRow.Cells(3), .Rows.Count))).Delete
        End With
        .Offset(-1).AutoFilter
        .Sort .Columns(2) ' Due Date
      End With
    Next
  End With
  Cells(1).Select

End Sub

Caveat:

This one loop technique will only work if the tool type in the demand table starts with the name of the tool from the storage table.


I've also added a tidied and fully documented version, so you can understand how it works:

Sub Demand_Minus_Storage()

  Const n_DemandHeaderRows As Long = 1
  Const i_SN_UTID   As Long = 1
  Const i_Due_Date  As Long = 2
  Const i_Tool_Type As Long = 5
  Const n_StorageHeaderRows As Long = 2
  Const i_Tool  As Long = 1
  Const i_QT    As Long = 3

  Dim rngRow As Range
  Dim ƒ As WorksheetFunction: Set ƒ = WorksheetFunction

  Dim storage_wb As Workbook
  Set storage_wb = Workbooks.Open("C:\Users\rosipov\Desktop\eliran\MFG - GSS\OpticLabStorage.xlsm")

  Dim Demand_WB As Workbook
  Set Demand_WB = Workbooks.Open("C:\Users\rosipov\Desktop\eliran\MFG - GSS\Demand_Optics " & Format(Now(), "dd.mm.yyyy") & ".xlsx")

  With storage_wb.Worksheets("Illuminator")
    ' Use the worksheet function "Match" to find the last storage used row
    ' Then loop through each storage row
    For Each rngRow In .Range(.Rows(n_StorageHeaderRows + 1), .Rows(ƒ.Match("*", .Columns(i_SN_UTID), -1))).Rows
      ' Skip the header rows and at the same time add at least one row after the end of the table
      With Demand_WB.Worksheets("Illuminators").UsedRange.Offset(n_DemandHeaderRows)
        ' Need to sort by tool type so the rows to be deleted are contiguous
        .Sort .Columns(i_Tool_Type)
        ' Back up to last header row and apply the filter
        ' The filter is for any tool type that starts with the tool in the current storage row
        .Offset(-1).AutoFilter Field:=i_Tool_Type, Criteria1:="=" & rngRow.Cells(i_Tool) & "*"
        ' Need to re-sort by date as we previously sorted by tool type
        .Sort .Columns(i_Due_Date)
        ' Grab the first visible contiguous area. There is always at least the one from the row(s) after the end of the table.
        ' If there are any matching tool tips, these will form an area preceding the end of table area.
        With .SpecialCells(xlCellTypeVisible).EntireRow.Areas(1)
          ' Make sure we don't delete more rows than were actually found.
          ' If none were found, empty rows at the end of the table get deleted.
          Range(.Rows(1), .Rows(ƒ.Min(rngRow.Cells(i_QT), .Rows.Count))).Delete
        End With
        ' Turn autofilter off and show all hidden rows
        .Offset(-n_DemandHeaderRows).AutoFilter
        ' Need to re-sort by date as hidden rows were not sorted in previous date sort
        .Sort .Columns(i_Due_Date)
      End With
    Next
  End With
  ' Tidy up
  Cells(1).Select

End Sub
robinCTS
  • 5,746
  • 14
  • 30
  • 37