Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Вивчайте Цикли | Основи VBA
Excel VBA для автоматизації бізнесу

Цикли

Свайпніть щоб показати меню

Кожна техніка, розглянута до цього, працювала лише з одним значенням за раз. Цикли дозволяють застосовувати одну й ту ж логіку до багатьох значень підряд — п’яти продуктів, п’ятисот замовлень, скільки б рядків не містила таблиця — без необхідності копіювати й вставляти один і той самий блок коду знову й знову.

For...Next

Повторює блок коду фіксовану, відому кількість разів:

Dim i As Long
For i = 1 To 5
    Debug.Print "Row " & i
Next i
 
' Step lets you skip or count backward
For i = 10 To 1 Step -1
    Debug.Print i
Next i

У першому циклі i починається з 1, код всередині виконується один раз із цим значенням, потім i автоматично збільшується на 1 і весь блок виконується знову — повторюється, поки i не перевищить 5, після чого цикл просто зупиняється і виконання продовжується після Next. Step змінює крок: Step -1 рахує у зворотному напрямку замість стандартного збільшення на 1, а Step 2 рахуватиме через два. Змінна циклу i не є особливим синтаксисом — це звичайна змінна типу Long, яку VBA оновлює за вас при кожному проході.

For Each

Проходить по кожному елементу колекції напряму, без необхідності знати їхню кількість чи керувати лічильником вручну:

Dim cell As Range
For Each cell In ThisWorkbook.Worksheets("Products").Range("B2:B6")
    Debug.Print cell.Value
Next cell

Тут cell по черзі приймає кожну окрему клітинку з діапазону B2:B6, і ви зчитуєте її вміст через .Value. Порівняйте це з For...Next: у For...Next ви рахуєте числа і використовуєте це число для пошуку; у For Each ви проходите безпосередньо по самих елементах, що виглядає природніше при роботі з діапазонами аркуша.

Do While

Повторюється, поки умова залишається True — цикл не знає наперед, скільки разів він виконається, що відрізняє його від For...Next:

Dim stock As Integer
stock = 134
Do While stock > 0
    stock = stock - 30    ' simulate selling in batches of 30
Loop
Debug.Print stock   ' whatever's left after the loop stops

VBA перевіряє stock > 0 перед кожним проходом циклу, включаючи перший. Простежте вручну: 134 → 104 → 74 → 44 → 14, потім умова перевіряється знову — 14 все ще більше 0, тому цикл виконується ще раз, отримуємо -16. Лише тоді stock > 0 повертає False, і цикл зупиняється зі stock на -16, а не рівно на 0 чи 14. Це варто уважно простежити вперше, оскільки це поширене джерело помилок на одну ітерацію: цикл Do While продовжує виконуватись, поки умова істинна на момент перевірки, навіть якщо дія всередині циклу виходить за межу, яку ви мали на увазі.

Do Until

Є також Do Until, який є дзеркальним відображенням Do While — він повторюється, поки умова є False, і зупиняється, щойно умова стає True, а не навпаки. Який з них виглядає природніше, залежить від того, як ви сформулюєте бізнес-правило вголос: "продовжувати, поки є залишки" підходить для Do While; "продовжувати, поки не закінчаться залишки" — для Do Until. Вони можуть давати однакову поведінку, просто сформульовану з різних боків.

Оператори виходу

Дозволяють вийти з циклу раніше, до досягнення його природної кінцевої умови:

For i = 1 To 100
    If i = 10 Then Exit For   ' stop the loop immediately
    Debug.Print i
Next i

Цей цикл налаштований рахувати до 100, але щойно i досягає 10, Exit For зупиняє його — нічого після Exit For не виконується, і виконання переходить одразу до рядка після Next i. Цей підхід використовують для пошуку у списку і зупинки, як тільки знайдено потрібне, замість непотрібної перевірки всіх решти елементів.

Об’єднання всього разом

Усі техніки з цього розділу — змінні, оператори, функції, умовна логіка і тепер цикли — поєднуються у процедурі, до якої цей розділ і вів:

Option Explicit
 
Sub CheckStockLevels()
 
    ' Sample data standing in for the Products table
    Dim products(1 To 5) As String
    Dim stockLevels(1 To 5) As Integer
    Dim reorderLevels(1 To 5) As Integer
    Dim i As Long
    Dim alertMessage As String
 
    products(1) = "Laptop Stand": stockLevels(1) = 58: reorderLevels(1) = 20
    products(2) = "Wireless Mouse": stockLevels(2) = 134: reorderLevels(2) = 30
    products(3) = "USB-C Hub": stockLevels(3) = 44: reorderLevels(3) = 15
    products(4) = "Monitor Arm": stockLevels(4) = 18: reorderLevels(4) = 10
    products(5) = "Keyboard": stockLevels(5) = 61: reorderLevels(5) = 20
 
    alertMessage = ""
 
    For i = 1 To 5
        Select Case stockLevels(i)
            Case Is <= reorderLevels(i)
                alertMessage = alertMessage & products(i) & _
                    " — REORDER NOW" & vbNewLine
            Case Is <= reorderLevels(i) + 10
                alertMessage = alertMessage & products(i) & _
                    " — watch closely" & vbNewLine
        End Select
    Next i
 
    If alertMessage = "" Then
        MsgBox "All products are adequately stocked."
    Else
        MsgBox "Stock Alerts:" & vbNewLine & alertMessage
    End If
End Sub
Покроковий розбір рядків коду
expand arrow
  • Dim products(1 To 5) As String і два подібних рядки нижче оголошують масиви — кожен з них є пронумерованим рядом з п’яти комірок замість однієї, тому products(1) — це назва першого продукту, products(2) — другого і так далі;
  • П’ять рядків із двокрапкою (:) між виразами об’єднують кілька присвоєнь в один рядок лише для зручності читання — products(1) = "Laptop Stand": stockLevels(1) = 58: reorderLevels(1) = 20 повністю еквівалентно запису цих присвоєнь на трьох окремих рядках;
  • For i = 1 To 5 ... Next i проходить по всіх п’яти продуктах по черзі, використовуючи i як лічильник циклу і як індекс для кожного масиву;
  • Select Case stockLevels(i) повторно виконує той самий діапазонний вибір із розділу 2.4, але тепер для реальних даних масиву замість одного жорстко заданого числа;
  • Case Is <= reorderLevels(i) спрацьовує для будь-якого продукту, запас якого впав до або нижче власного рівня дозамовлення — зверніть увагу, reorderLevels(i) тут також змінна, а не фіксоване число, тому кожен продукт оцінюється за власним порогом, а не за спільним для всіх;
  • alertMessage = alertMessage & ... & vbNewLine поступово формує рядок, додаючи по одному рядку за раз — vbNewLine це вбудована константа для переносу рядка, тому кожен позначений продукт з’явиться на окремому рядку у фінальному повідомленні;
  • Фінальна перевірка If alertMessage = "" Then визначає, який із двох варіантів MsgBox побачить користувач — порожній рядок означає, що цикл не знайшов нічого, що варто було б позначити.

Запустіть це, і ви побачите, що Моніторне кріплення позначено як "уважно стежити" (18 одиниць проти рівня поповнення 10) — вручну простежте виконання циклу для i = 4, якщо хочете точно переконатися, чому саме цей товар потрапляє під другу умову Case, а не під першу. Ця процедура використовує масиви, цикл, Select Case і формування рядків, які працюють разом. Це вже майже логіка виробничого рівня, просто вона працює з тестовими даними, введеними безпосередньо в код, а не з реальною таблицею.

Завдання

  1. Скопіюйте CheckStockLevels у свою книгу та запустіть. Переконайтеся, що повідомлення відповідає скріншоту.
  2. Змініть залишок Wireless Mouse на 25 і перезапустіть — тепер він також має відображатися як "уважно стежити".
  3. Додайте цикл Do While нижче, який імітує продаж 15 одиниць Laptop Stand за раз, поки залишок не зменшиться до 20 або менше, виводячи поточний залишок у Вікно негайного виконання після кожного продажу.
  4. Завдання з підвищеною складністю: перепишіть цикл For i = 1 To 5, використовуючи For Each по Variant-масиву — чи залишиться логіка коректною?
Підказка
expand arrow

2. Зміна залишку Wireless Mouse

  • Знайти рядок, який встановлює дані для Wireless Mouse: products(2) = "Wireless Mouse": stockLevels(2) = 134: reorderLevels(2) = 30.
  • Потрібно змінити лише середнє число (134) на 25 — назву продукту та рівень поповнення залишити без змін.
  • Перед запуском вручну визначити, який Case спрацює: чи 25 ≤ 30 (рівень поповнення)? Порівняти це саме з рядком Case Is <= reorderLevels(i), а не з другим.

3. Імітація пакетних продажів з Do While

  • Потрібна змінна для поточного залишку Laptop Stand — почати з того ж значення, що вже знаходиться у stockLevels(1) (58), щоб не вводити нове число, яке може не співпадати з іншими частинами макросу.
  • Умова циклу повинна перевіряти, чи залишок більший за 20 — як тільки перевірка покаже 20 або менше, цикл зупиняється.
  • Віднімати 15 за кожну ітерацію та виводити нове значення одразу після віднімання — не до цього — щоб кожне виведене число відображало завершений продаж.
  • Пройти це на папері: 58 → 43 → 28 → 13. Звернути увагу, що останнє значення опускається нижче 20, а не дорівнює йому — це така ж поведінка "перепаду" циклу Do While, яку раніше показувала діаграма циклів у цьому розділі, а не помилка.
Розв'язок
expand arrow

Пункт 2 — у межах CheckStockLevels змінити лише одне число:

products(2) = "Wireless Mouse": stockLevels(2) = 25: reorderLevels(2) = 30

Запустити Sub ще раз.

Пункт 3 — додати це під наявним кодом, все ще всередині CheckStockLevels (до End Sub):

    ' --- Simulate selling Laptop Stand in batches of 15 ---
    Dim laptopStandStock As Integer
    laptopStandStock = stockLevels(1)

    Do While laptopStandStock > 20
        laptopStandStock = laptopStandStock - 15
        Debug.Print laptopStandStock
    Loop
Все було зрозуміло?

Як ми можемо покращити це?

Дякуємо за ваш відгук!

Секція 2. Розділ 5

Запитати АІ

expand

Запитати АІ

ChatGPT

Запитайте про що завгодно або спробуйте одне із запропонованих запитань, щоб почати наш чат

Цикли

Кожна техніка, розглянута до цього, працювала лише з одним значенням за раз. Цикли дозволяють застосовувати одну й ту ж логіку до багатьох значень підряд — п’яти продуктів, п’ятисот замовлень, скільки б рядків не містила таблиця — без необхідності копіювати й вставляти один і той самий блок коду знову й знову.

For...Next

Повторює блок коду фіксовану, відому кількість разів:

Dim i As Long
For i = 1 To 5
    Debug.Print "Row " & i
Next i
 
' Step lets you skip or count backward
For i = 10 To 1 Step -1
    Debug.Print i
Next i

У першому циклі i починається з 1, код всередині виконується один раз із цим значенням, потім i автоматично збільшується на 1 і весь блок виконується знову — повторюється, поки i не перевищить 5, після чого цикл просто зупиняється і виконання продовжується після Next. Step змінює крок: Step -1 рахує у зворотному напрямку замість стандартного збільшення на 1, а Step 2 рахуватиме через два. Змінна циклу i не є особливим синтаксисом — це звичайна змінна типу Long, яку VBA оновлює за вас при кожному проході.

For Each

Проходить по кожному елементу колекції напряму, без необхідності знати їхню кількість чи керувати лічильником вручну:

Dim cell As Range
For Each cell In ThisWorkbook.Worksheets("Products").Range("B2:B6")
    Debug.Print cell.Value
Next cell

Тут cell по черзі приймає кожну окрему клітинку з діапазону B2:B6, і ви зчитуєте її вміст через .Value. Порівняйте це з For...Next: у For...Next ви рахуєте числа і використовуєте це число для пошуку; у For Each ви проходите безпосередньо по самих елементах, що виглядає природніше при роботі з діапазонами аркуша.

Do While

Повторюється, поки умова залишається True — цикл не знає наперед, скільки разів він виконається, що відрізняє його від For...Next:

Dim stock As Integer
stock = 134
Do While stock > 0
    stock = stock - 30    ' simulate selling in batches of 30
Loop
Debug.Print stock   ' whatever's left after the loop stops

VBA перевіряє stock > 0 перед кожним проходом циклу, включаючи перший. Простежте вручну: 134 → 104 → 74 → 44 → 14, потім умова перевіряється знову — 14 все ще більше 0, тому цикл виконується ще раз, отримуємо -16. Лише тоді stock > 0 повертає False, і цикл зупиняється зі stock на -16, а не рівно на 0 чи 14. Це варто уважно простежити вперше, оскільки це поширене джерело помилок на одну ітерацію: цикл Do While продовжує виконуватись, поки умова істинна на момент перевірки, навіть якщо дія всередині циклу виходить за межу, яку ви мали на увазі.

Do Until

Є також Do Until, який є дзеркальним відображенням Do While — він повторюється, поки умова є False, і зупиняється, щойно умова стає True, а не навпаки. Який з них виглядає природніше, залежить від того, як ви сформулюєте бізнес-правило вголос: "продовжувати, поки є залишки" підходить для Do While; "продовжувати, поки не закінчаться залишки" — для Do Until. Вони можуть давати однакову поведінку, просто сформульовану з різних боків.

Оператори виходу

Дозволяють вийти з циклу раніше, до досягнення його природної кінцевої умови:

For i = 1 To 100
    If i = 10 Then Exit For   ' stop the loop immediately
    Debug.Print i
Next i

Цей цикл налаштований рахувати до 100, але щойно i досягає 10, Exit For зупиняє його — нічого після Exit For не виконується, і виконання переходить одразу до рядка після Next i. Цей підхід використовують для пошуку у списку і зупинки, як тільки знайдено потрібне, замість непотрібної перевірки всіх решти елементів.

Об’єднання всього разом

Усі техніки з цього розділу — змінні, оператори, функції, умовна логіка і тепер цикли — поєднуються у процедурі, до якої цей розділ і вів:

Option Explicit
 
Sub CheckStockLevels()
 
    ' Sample data standing in for the Products table
    Dim products(1 To 5) As String
    Dim stockLevels(1 To 5) As Integer
    Dim reorderLevels(1 To 5) As Integer
    Dim i As Long
    Dim alertMessage As String
 
    products(1) = "Laptop Stand": stockLevels(1) = 58: reorderLevels(1) = 20
    products(2) = "Wireless Mouse": stockLevels(2) = 134: reorderLevels(2) = 30
    products(3) = "USB-C Hub": stockLevels(3) = 44: reorderLevels(3) = 15
    products(4) = "Monitor Arm": stockLevels(4) = 18: reorderLevels(4) = 10
    products(5) = "Keyboard": stockLevels(5) = 61: reorderLevels(5) = 20
 
    alertMessage = ""
 
    For i = 1 To 5
        Select Case stockLevels(i)
            Case Is <= reorderLevels(i)
                alertMessage = alertMessage & products(i) & _
                    " — REORDER NOW" & vbNewLine
            Case Is <= reorderLevels(i) + 10
                alertMessage = alertMessage & products(i) & _
                    " — watch closely" & vbNewLine
        End Select
    Next i
 
    If alertMessage = "" Then
        MsgBox "All products are adequately stocked."
    Else
        MsgBox "Stock Alerts:" & vbNewLine & alertMessage
    End If
End Sub
Покроковий розбір рядків коду
expand arrow
  • Dim products(1 To 5) As String і два подібних рядки нижче оголошують масиви — кожен з них є пронумерованим рядом з п’яти комірок замість однієї, тому products(1) — це назва першого продукту, products(2) — другого і так далі;
  • П’ять рядків із двокрапкою (:) між виразами об’єднують кілька присвоєнь в один рядок лише для зручності читання — products(1) = "Laptop Stand": stockLevels(1) = 58: reorderLevels(1) = 20 повністю еквівалентно запису цих присвоєнь на трьох окремих рядках;
  • For i = 1 To 5 ... Next i проходить по всіх п’яти продуктах по черзі, використовуючи i як лічильник циклу і як індекс для кожного масиву;
  • Select Case stockLevels(i) повторно виконує той самий діапазонний вибір із розділу 2.4, але тепер для реальних даних масиву замість одного жорстко заданого числа;
  • Case Is <= reorderLevels(i) спрацьовує для будь-якого продукту, запас якого впав до або нижче власного рівня дозамовлення — зверніть увагу, reorderLevels(i) тут також змінна, а не фіксоване число, тому кожен продукт оцінюється за власним порогом, а не за спільним для всіх;
  • alertMessage = alertMessage & ... & vbNewLine поступово формує рядок, додаючи по одному рядку за раз — vbNewLine це вбудована константа для переносу рядка, тому кожен позначений продукт з’явиться на окремому рядку у фінальному повідомленні;
  • Фінальна перевірка If alertMessage = "" Then визначає, який із двох варіантів MsgBox побачить користувач — порожній рядок означає, що цикл не знайшов нічого, що варто було б позначити.

Запустіть це, і ви побачите, що Моніторне кріплення позначено як "уважно стежити" (18 одиниць проти рівня поповнення 10) — вручну простежте виконання циклу для i = 4, якщо хочете точно переконатися, чому саме цей товар потрапляє під другу умову Case, а не під першу. Ця процедура використовує масиви, цикл, Select Case і формування рядків, які працюють разом. Це вже майже логіка виробничого рівня, просто вона працює з тестовими даними, введеними безпосередньо в код, а не з реальною таблицею.

Завдання

  1. Скопіюйте CheckStockLevels у свою книгу та запустіть. Переконайтеся, що повідомлення відповідає скріншоту.
  2. Змініть залишок Wireless Mouse на 25 і перезапустіть — тепер він також має відображатися як "уважно стежити".
  3. Додайте цикл Do While нижче, який імітує продаж 15 одиниць Laptop Stand за раз, поки залишок не зменшиться до 20 або менше, виводячи поточний залишок у Вікно негайного виконання після кожного продажу.
  4. Завдання з підвищеною складністю: перепишіть цикл For i = 1 To 5, використовуючи For Each по Variant-масиву — чи залишиться логіка коректною?
Підказка
expand arrow

2. Зміна залишку Wireless Mouse

  • Знайти рядок, який встановлює дані для Wireless Mouse: products(2) = "Wireless Mouse": stockLevels(2) = 134: reorderLevels(2) = 30.
  • Потрібно змінити лише середнє число (134) на 25 — назву продукту та рівень поповнення залишити без змін.
  • Перед запуском вручну визначити, який Case спрацює: чи 25 ≤ 30 (рівень поповнення)? Порівняти це саме з рядком Case Is <= reorderLevels(i), а не з другим.

3. Імітація пакетних продажів з Do While

  • Потрібна змінна для поточного залишку Laptop Stand — почати з того ж значення, що вже знаходиться у stockLevels(1) (58), щоб не вводити нове число, яке може не співпадати з іншими частинами макросу.
  • Умова циклу повинна перевіряти, чи залишок більший за 20 — як тільки перевірка покаже 20 або менше, цикл зупиняється.
  • Віднімати 15 за кожну ітерацію та виводити нове значення одразу після віднімання — не до цього — щоб кожне виведене число відображало завершений продаж.
  • Пройти це на папері: 58 → 43 → 28 → 13. Звернути увагу, що останнє значення опускається нижче 20, а не дорівнює йому — це така ж поведінка "перепаду" циклу Do While, яку раніше показувала діаграма циклів у цьому розділі, а не помилка.
Розв'язок
expand arrow

Пункт 2 — у межах CheckStockLevels змінити лише одне число:

products(2) = "Wireless Mouse": stockLevels(2) = 25: reorderLevels(2) = 30

Запустити Sub ще раз.

Пункт 3 — додати це під наявним кодом, все ще всередині CheckStockLevels (до End Sub):

    ' --- Simulate selling Laptop Stand in batches of 15 ---
    Dim laptopStandStock As Integer
    laptopStandStock = stockLevels(1)

    Do While laptopStandStock > 20
        laptopStandStock = laptopStandStock - 15
        Debug.Print laptopStandStock
    Loop
Все було зрозуміло?

Як ми можемо покращити це?

Дякуємо за ваш відгук!

Секція 2. Розділ 5
some-alt