{
  "assessmentTests": {
    "sql_test": {
      "name": "Тест SQL",
      "desc": "30 сценарних запитань з фільтрування, з'єднань, агрегації, підзапитів та вікнових функцій — дізнайтеся, чи ваш SQL відповідає тому, що роботодавець має на увазі під SQL-профільністю.",
      "recommendation": "Ваш профіль навичок SQL",
      "results": {
        "beginner": {
          "name": "Новачок",
          "desc": "Ви можете написати робочий SELECT-запит та фільтрувати за кількома умовами, але запитання, на яких ви помилялися, групуються навколо NULL-обробки та механіки з'єднань, а не синтаксису — порівняння стовпця з NULL через =, що насправді зберігає LEFT JOIN, як працюють межі BETWEEN. Це не про слабкість в роботі з БД; це специфічні правила, які бентежать людей, які вивчали SQL методом проб і помилок, а не зі стандарту. Вони важливі на роботі, тому що кожне з них — це місце, де запит повертає результат, що виглядає правдоподібно, але неправильно.",
          "recommendation": "Почніть з трьох речей у такому порядку: чому WHERE col = NULL ніколи не знайде нічого (замість цього потрібен IS NULL), як INNER JOIN відкидає неспівпадаючі рядки, а LEFT JOIN їх зберігає, та точні межі, які включає BETWEEN. Mode Analytics SQL tutorial та документація PostgreSQL обидва охоплюють усі три з виконуваними прикладами."
        },
        "intermediate": {
          "name": "Проміжний рівень",
          "desc": "Ви комфортно обробляєте щоденні звітні запити — з'єднання, GROUP BY, простого фільтрування — і не будете сповільнені рутинною роботою з дашбордів або ad-hoc-аналізом. Розрив між цим рівнем і Продвинутим здебільшого в тому, що відбувається, коли пункти взаємодіють: пункт WHERE на з'єднаній таблиці тихо перетворює LEFT JOIN назад в INNER JOIN, з'єднання, яке множить кількість рядків перед застосуванням агрегату до них, NOT IN, який тихо нічого не повертає, тому що в підзапит потрапив один NULL. Це тип помилок, які проходять швидку перевірку очима та з'являються лише коли хтось порівнює загальне число з іншим звітом.",
          "recommendation": "Зосередьтеся на тому, як пункти взаємодіють, а не на тому, що кожен робить окремо: WHERE-фільтрування на колонках праворуч від LEFT JOIN, множення кількості рядків від one-to-many з'єднань перед застосуванням агрегату, та чому NOT IN ламається на присутність NULL (EXISTS зазвичай не). Потім HAVING проти WHERE, тому що цей розподіл бентежить людей, які вже знають обидва пункти окремо."
        },
        "advanced": {
          "name": "Продвинутий рівень",
          "desc": "Це рівень, який найчастіше мають на увазі роботодавці під «сильний SQL». Ви читаєте багатоз'єднаний запит й можете передбачити кількість його рядків перед запуском, ви знаєте, чому змінився результат, а не просто те, що змінився, і ви сягаєте за CTE або вікновою функцією замість вкладеного підзапиту, коли це ясніший інструмент. Те, що відокремлює цей рівень від вершини, — захисна сторона роботи: знання того, яку функцію ранжування використовувати, коли рішення важливі, що ізолює транзакція від паралельної сесії, та що насправді робить відсутнє правило ON DELETE на рівні БД.",
          "recommendation": "Глибше заходьте в частини, які захищають дані, яких торкаються інші люди: різниця між RANK, DENSE_RANK та ROW_NUMBER при рішеннях, що робить COMMIT видимим і для кого, та поведінка зовнішнього ключа при DELETE. Використовуйте глибокі статті The Index newsletter або SQL for Devs про вікнові функції та ізоляцію транзакцій як наступний крок."
        },
        "expert": {
          "name": "Експерт",
          "desc": "Ви набрали максимальні бали в кожній секції — фільтрування та NULL-семантика, з'єднання та операції над множинами, агрегація та підзапити, вікнові функції, CTE та обмеження. Практично це означає, що вам можна дати чужий запит на з'єднання та пояснити, чому він повертає кількість рядків, яку повертає, а не просто що синтаксис говорить, що повинен повернути — це важша та цінніша навичка. На цьому рівні сама мова рідко є обмежуючим фактором; обмеження зазвичай залежить від дизайну схеми або розміру даних під кодом.",
          "recommendation": "Повернення тепер залежить від планів виконання та дизайну: читання висновків EXPLAIN перед припущенням, що запит повільний, стратегія індексування як компроміс проти вартості запису, а не вільна перемога, та рішення про нормалізацію, які витримують зростання схеми. Якщо вас відбирають на роботу, опишіть помилку запиту, схожу на множення в з'єднанні або пастку NOT IN/NULL, яку ви знайшли в production, а не назвіть функції мови — це демонструє мислення, а не просто словниковий запас."
        }
      },
      "questions": [
        {
          "question": "Таблиця має nullable-стовпець age. Ви запускаєте SELECT * FROM users WHERE age = NULL. Скільки рядків повертає цей запит, навіть якщо декілька рядків мають age встановленим на NULL?",
          "options": [
            {
              "icon": "",
              "label": "Кожен рядок, де age має NULL, тому що = порівнює NULL як будь-яке інше значення"
            },
            {
              "icon": "",
              "label": "Нуль — порівняння будь-чого з NULL через = дає UNKNOWN, ніколи TRUE, тож жоден рядок не підходить; натомість потрібен IS NULL"
            },
            {
              "icon": "",
              "label": "Помилка синтаксису — NULL не може з'являтися праворуч від ="
            },
            {
              "icon": "",
              "label": "Кожен рядок у таблиці, тому що порівняння з NULL за замовчуванням дає TRUE"
            }
          ]
        },
        {
          "question": "Ви запускаєте SELECT DISTINCT department, role FROM employees. Від чого DISTINCT видаляє дублікати?",
          "options": [
            {
              "icon": "",
              "label": "Від комбінації department та role разом — рядок видаляється лише якщо обидва стовпці точно збігаються з іншим рядком"
            },
            {
              "icon": "",
              "label": "Тільки від дублікатних значень department, зберігаючи кожен role"
            },
            {
              "icon": "",
              "label": "Тільки від дублікатних значень role, зберігаючи кожен department"
            },
            {
              "icon": "",
              "label": "Від нічого — DISTINCT працює лише з одним стовпцем"
            }
          ]
        },
        {
          "question": "Стовпець name фільтрується з WHERE name LIKE 'A_'. Який із цих значень підходить: 'A', 'Al', 'Ana', 'Ally'?",
          "options": [
            {
              "icon": "",
              "label": "'A' — підкреслення опціональне та підходить нулю або більше символів"
            },
            {
              "icon": "",
              "label": "'Al' — підкреслення підходить рівно одному символу, тож LIKE 'A_' підходить будь-якому двосимвольному рядку, що починається з A"
            },
            {
              "icon": "",
              "label": "'Ana' та 'Ally' — підкреслення підходить будь-якій кількості символів в кінці"
            },
            {
              "icon": "",
              "label": "Усі чотири значення підходять, тому що LIKE ігнорує довжину"
            }
          ]
        },
        {
          "question": "Стовпець price фільтрується з WHERE price BETWEEN 10 AND 20. Чи включаються рядки з price рівно 10 або рівно 20?",
          "options": [
            {
              "icon": "",
              "label": "Ні — BETWEEN виключає обидва кінця"
            },
            {
              "icon": "",
              "label": "Так — BETWEEN включаючий з обох боків, еквівалентний price >= 10 AND price <= 20"
            },
            {
              "icon": "",
              "label": "Лише price = 10 включається; верхня межа виключаюча"
            },
            {
              "icon": "",
              "label": "Лише price = 20 включається; нижня межа виключаюча"
            }
          ]
        },
        {
          "question": "Таблиця orders має 10 рядків, 3 з них мають NULL shipped_date. Що повертає SELECT COUNT(*) FROM orders, та що повертає SELECT COUNT(shipped_date) FROM orders?",
          "options": [
            {
              "icon": "",
              "label": "10, потім 10 — COUNT завжди рахує рядки незалежно від NULL"
            },
            {
              "icon": "",
              "label": "7, потім 7 — обидві форми пропускають NULL-рядки"
            },
            {
              "icon": "",
              "label": "10, потім 7 — COUNT(*) рахує кожен рядок, COUNT(стовпець) рахує тільки рядки, де той стовпець не NULL"
            },
            {
              "icon": "",
              "label": "10, потім 3 — COUNT(стовпець) рахує тільки NULL-значення"
            }
          ]
        },
        {
          "question": "Ви запускаєте SELECT name, salary FROM employees ORDER BY 2 DESC. На що посилається 2?",
          "options": [
            {
              "icon": "",
              "label": "Помилка синтаксису — ORDER BY приймає тільки назви стовпців, не числа"
            },
            {
              "icon": "",
              "label": "На другий рядок результату"
            },
            {
              "icon": "",
              "label": "На буквальне значення 2, використане як tiebreaker"
            },
            {
              "icon": "",
              "label": "На другий стовпець у списку SELECT, salary — ORDER BY приймає номер позиції стовпця як скорочення"
            }
          ]
        },
        {
          "question": "У стандартному SQL, на що оцінюється 'Ana' || ' ' || 'Lee'?",
          "options": [
            {
              "icon": "",
              "label": "Помилка синтаксису — SQL не має оператора конкатенації"
            },
            {
              "icon": "",
              "label": "3 — || трактується як булів OR та повертає підрахунок"
            },
            {
              "icon": "",
              "label": "'AnaLee' — || конкатенує без збереження пробілів"
            },
            {
              "icon": "",
              "label": "'Ana Lee' — || є стандартним SQL-оператором конкатенації рядків"
            }
          ]
        },
        {
          "question": "Яке з цих рівнозначне WHERE status IN ('open', 'pending', 'review')?",
          "options": [
            {
              "icon": "",
              "label": "WHERE status = 'open' AND status = 'pending' AND status = 'review'"
            },
            {
              "icon": "",
              "label": "WHERE status != 'open' OR status != 'pending' OR status != 'review'"
            },
            {
              "icon": "",
              "label": "WHERE status = 'open' OR status = 'pending' OR status = 'review'"
            },
            {
              "icon": "",
              "label": "WHERE status LIKE 'open,pending,review'"
            }
          ]
        },
        {
          "question": "customers має 100 рядків; 20 з них ніколи не розмістили замовлення. Ви запускаєте SELECT c.id FROM customers c INNER JOIN orders o ON c.id = o.customer_id. Чи з'являються 20 клієнтів без замовлень у результаті?",
          "options": [
            {
              "icon": "",
              "label": "Так, один раз кожен, з o.id показаним як NULL"
            },
            {
              "icon": "",
              "label": "Так, але тільки якщо вони також з'являються у WHERE-пункті"
            },
            {
              "icon": "",
              "label": "Ні — INNER JOIN повертає тільки рядки, які мають відповідність в обох таблицях, тож клієнти без замовлень повністю видаляються"
            },
            {
              "icon": "",
              "label": "Так, дубльовані один раз на кожен стовпець в orders"
            }
          ]
        },
        {
          "question": "Ви хочете кожного клієнта, незалежно від того, чи мають вони замовлення, тож ви пишете SELECT c.id, o.total FROM customers c LEFT JOIN orders o ON c.id = o.customer_id WHERE o.total > 100. Чи це все ще повертає клієнтів без замовлень?",
          "options": [
            {
              "icon": "",
              "label": "Ні — фільтрування на o.total у WHERE-пункті відкидає NULL-рядки, які LEFT JOIN виробив для неспівпадаючих клієнтів, тож воно поводиться як INNER JOIN"
            },
            {
              "icon": "",
              "label": "Так — LEFT JOIN завжди зберігає кожен рядок з customers, незалежно від того, що йде далі"
            },
            {
              "icon": "",
              "label": "Так, з o.total показаним як 0 для клієнтів без замовлень"
            },
            {
              "icon": "",
              "label": "Ні — LEFT JOIN тихо перетворюється на RIGHT JOIN, коли додається WHERE-пункт"
            }
          ]
        },
        {
          "question": "Таблиця employees має стовпець id та стовпець manager_id, який посилається на інший рядок id. Щоб вивести кожного працівника поряд з назвою його менеджера, ви з'єднуєте таблицю саму з собою: SELECT e.name, m.name FROM employees e JOIN employees m ON e.manager_id = m.id. Як називається цей паттерн?",
          "options": [
            {
              "icon": "",
              "label": "Перехресне з'єднання (cross join) — кожен працівник відповідає кожному менеджеру"
            },
            {
              "icon": "",
              "label": "Рекурсивне з'єднання — воно отримує повний управлінський ланцюг"
            },
            {
              "icon": "",
              "label": "Self-join — та сама таблиця з'єднується сама з собою за допомогою двох різних псевдонімів"
            },
            {
              "icon": "",
              "label": "Це невалідний SQL — таблиця не може з'єднуватися сама з собою"
            }
          ]
        },
        {
          "question": "Два SELECT-запити з одними й тими ж стовпцями комбінуються з UNION. Якщо обидва запити повертають однаковий рядок, скільки копій цього рядка з'являються в кінцевому результаті?",
          "options": [
            {
              "icon": "",
              "label": "Одна — UNION видаляє дублікатні рядки по всьому комбінованому результату; UNION ALL зберіг би обидві копії"
            },
            {
              "icon": "",
              "label": "Дві — UNION зберігає кожен рядок з обох запитів"
            },
            {
              "icon": "",
              "label": "Нуль — UNION видаляє будь-який рядок, що з'являється в обох запитах"
            },
            {
              "icon": "",
              "label": "Залежить від того, який запит першим указав рядок"
            }
          ]
        },
        {
          "question": "Таблиця sizes має 3 рядки та colors має 4 рядки. Скільки рядків повертає SELECT * FROM sizes CROSS JOIN colors?",
          "options": [
            {
              "icon": "",
              "label": "7 — CROSS JOIN додає кількості рядків разом"
            },
            {
              "icon": "",
              "label": "12 — CROSS JOIN повертає кожну можливу комбінацію рядків з обох таблиць (3 x 4)"
            },
            {
              "icon": "",
              "label": "3 — CROSS JOIN повертає один рядок на рядок у першій таблиці"
            },
            {
              "icon": "",
              "label": "0 — CROSS JOIN потребує ON-умови або нічого не повертає"
            }
          ]
        },
        {
          "question": "orders має 1 рядок для замовлення #100, а order_items має 3 рядки для замовлення #100 (один на позицію). Ви запускаєте SELECT o.id, o.total FROM orders o JOIN order_items i ON o.id = i.order_id WHERE o.id = 100. Скільки рядків повертається для замовлення #100?",
          "options": [
            {
              "icon": "",
              "label": "3 — з'єднання виробляє один вихідний рядок на кожен відповідаючий рядок order_items, тож одиничний рядок замовлення #100 повторюється один раз на позицію"
            },
            {
              "icon": "",
              "label": "1 — orders має тільки один рядок для замовлення #100, тож з'єднання не може виробити більше"
            },
            {
              "icon": "",
              "label": "4 — один рядок для замовлення плюс один на позицію"
            },
            {
              "icon": "",
              "label": "0 — з'єднання однорядкової таблиці з трирядковою таблицею на non-unique-ключ не вдається"
            }
          ]
        },
        {
          "question": "SELECT c.name, o.id FROM customers c RIGHT JOIN orders o ON c.id = o.customer_id повертає ті ж рядки, що й яке з цих?",
          "options": [
            {
              "icon": "",
              "label": "SELECT c.name, o.id FROM customers c INNER JOIN orders o ON c.id = o.customer_id"
            },
            {
              "icon": "",
              "label": "SELECT c.name, o.id FROM orders o LEFT JOIN customers c ON c.id = o.customer_id — замінити порядок таблиць та використовувати LEFT JOIN замість RIGHT JOIN еквівалентно"
            },
            {
              "icon": "",
              "label": "SELECT c.name, o.id FROM customers c LEFT JOIN orders o ON c.id = o.customer_id"
            },
            {
              "icon": "",
              "label": "SELECT c.name, o.id FROM orders o CROSS JOIN customers c"
            }
          ]
        },
        {
          "question": "У стандартному SQL ви запускаєте SELECT department, name, AVG(salary) FROM employees GROUP BY department. Це валідний запит?",
          "options": [
            {
              "icon": "",
              "label": "Так — GROUP BY потребує тільки department, тому що він вказаний першим"
            },
            {
              "icon": "",
              "label": "Ні — name вибирається, але ні агрегований, ні вказаний у GROUP BY, а стандартний SQL вимагає, щоб кожен non-aggregated вибраний стовпець з'являвся у GROUP BY-пункті"
            },
            {
              "icon": "",
              "label": "Так — SQL автоматично вибирає один довільний name на department"
            },
            {
              "icon": "",
              "label": "Ні — AVG() не можна комбінувати з GROUP BY в одному запиті"
            }
          ]
        },
        {
          "question": "Ви хочете department, в якому середня зарплата перевищує 80000. Який пункт фільтрує на агрегованому значенні типу AVG(salary) після групування — WHERE або HAVING?",
          "options": [
            {
              "icon": "",
              "label": "WHERE — HAVING використовується тільки з UNION-запитами"
            },
            {
              "icon": "",
              "label": "Будь-який працює ідентично з функціями агрегації"
            },
            {
              "icon": "",
              "label": "Ні один — агрегована фільтрація потребує підзапиту"
            },
            {
              "icon": "",
              "label": "HAVING — WHERE фільтрує окремі рядки перед групуванням, HAVING фільтрує групи після агрегації"
            }
          ]
        },
        {
          "question": "Ви пишете SELECT salary * 1.1 AS new_salary FROM employees WHERE new_salary > 50000. Це запускається?",
          "options": [
            {
              "icon": "",
              "label": "Так — псевдоніми, визначені в SELECT, завжди доступні WHERE в тому ж запиті"
            },
            {
              "icon": "",
              "label": "Так, але тільки для числових псевдонімів"
            },
            {
              "icon": "",
              "label": "Ні — AS не дозволяється всередину WHERE-фільтрованого запиту"
            },
            {
              "icon": "",
              "label": "Ні — WHERE оцінюється перед SELECT, який присвоює псевдонім new_salary, тож псевдонім ще не існує на цей момент виконання"
            }
          ]
        },
        {
          "question": "SELECT name FROM employees e WHERE salary > (SELECT AVG(salary) FROM employees WHERE department = e.department). Чому це називається корельованим підзапитом?",
          "options": [
            {
              "icon": "",
              "label": "Тому що він використовує JOIN замість WHERE-пункту"
            },
            {
              "icon": "",
              "label": "Внутрішній підзапит посилається на e.department з зовнішнього запиту, тож він повинен бути переоцінений для кожного рядка, який розглядає зовнішній запит"
            },
            {
              "icon": "",
              "label": "Тому що він повертає більше одного стовпця"
            },
            {
              "icon": "",
              "label": "Тому що він запускається рівно один раз перед початком зовнішнього запиту"
            }
          ]
        },
        {
          "question": "Підзапит SELECT manager_id FROM employees повертає деякі NULL-значення разом з реальними id. Ви запускаєте SELECT name FROM employees WHERE id NOT IN (SELECT manager_id FROM employees). Що відбувається?",
          "options": [
            {
              "icon": "",
              "label": "Це повертає кожного працівника, який не є менеджером, ігноруючи NULL"
            },
            {
              "icon": "",
              "label": "Це повертає нуль рядків — один NULL у NOT IN-списку робить кожне порівняння UNKNOWN, тож жоден рядок не може задовольнити умову"
            },
            {
              "icon": "",
              "label": "Це піднімає помилку, тому що NOT IN не можна використовувати з підзапитами"
            },
            {
              "icon": "",
              "label": "Це повертає кожного працівника, оскільки NULL трактується як підстановочний символ"
            }
          ]
        },
        {
          "question": "SELECT name FROM customers c WHERE EXISTS (SELECT 1 FROM orders o WHERE o.customer_id = c.id). Що це повертає?",
          "options": [
            {
              "icon": "",
              "label": "Кожного клієнта, який має принаймні один рядок в orders — EXISTS тільки перевіряє, чи повертає підзапит якісь рядки, не те, які значення вони містять"
            },
            {
              "icon": "",
              "label": "Кожного клієнта, тому що SELECT 1 завжди повертає true"
            },
            {
              "icon": "",
              "label": "Помилку, тому що підзапит вибирає число замість назви стовпця"
            },
            {
              "icon": "",
              "label": "Тільки клієнтів рівно з одним замовленням"
            }
          ]
        },
        {
          "question": "Ви пишете SELECT name, (SELECT order_id FROM orders WHERE customer_id = c.id) AS last_order FROM customers c, та дан клієнт має 3 рядки в orders. Що відбувається, коли цей запит запускається?",
          "options": [
            {
              "icon": "",
              "label": "Це повертає перший відповідаючий order_id та тихо ігнорує інші два"
            },
            {
              "icon": "",
              "label": "Це повертає розділений комами список всіх трьох order_ids"
            },
            {
              "icon": "",
              "label": "Це повертає 3 рядки для цього клієнта, один на замовлення"
            },
            {
              "icon": "",
              "label": "Це піднімає помилку при виконанні — скалярний підзапит у SELECT-списку повинен повернути максимум один рядок, а цей повертає три"
            }
          ]
        },
        {
          "question": "Чотири рядки зв'язані за найвищим результатом. Використовуючи RANK() ORDER BY score DESC, усі чотири отримують rank 1. Який rank отримує наступний рядок вниз?",
          "options": [
            {
              "icon": "",
              "label": "5 — RANK() залишає розрив, рівний кількості зв'язаних рядків перед продовженням"
            },
            {
              "icon": "",
              "label": "2 — RANK() завжди збільшується рівно на один після будь-якого зв'язування"
            },
            {
              "icon": "",
              "label": "1 — кожен наступний рядок також отримує rank 1"
            },
            {
              "icon": "",
              "label": "4 — RANK() перезапускає лічення з кількості зв'язань"
            }
          ]
        },
        {
          "question": "Чотири рядки зв'язані за найвищим результатом. Використовуючи DENSE_RANK() ORDER BY score DESC, усі чотири отримують rank 1. Який rank отримує наступний рядок вниз?",
          "options": [
            {
              "icon": "",
              "label": "5 — DENSE_RANK() поводиться точно як RANK()"
            },
            {
              "icon": "",
              "label": "1 — DENSE_RANK() присвоює той же rank кожному решту рядку"
            },
            {
              "icon": "",
              "label": "2 — DENSE_RANK() ніколи не залишає розривів, тож наступне відмінне значення завжди отримує наступний послідовний rank"
            },
            {
              "icon": "",
              "label": "3 — DENSE_RANK() пропускає один rank на одну групу зв'язування"
            }
          ]
        },
        {
          "question": "SUM(amount) OVER (PARTITION BY region ORDER BY amount) додано до запиту. Що робить PARTITION BY region тут?",
          "options": [
            {
              "icon": "",
              "label": "Це перезапускає проточну суму окремо для кожного region, замість накопичення по всьому набору результатів"
            },
            {
              "icon": "",
              "label": "Це фільтрує результати в один region"
            },
            {
              "icon": "",
              "label": "Це групує та згортає рядки в один на region, як GROUP BY"
            },
            {
              "icon": "",
              "label": "Це сортує region в алфавітному порядку перед сумуванням"
            }
          ]
        },
        {
          "question": "ROW_NUMBER() OVER (ORDER BY score DESC) застосовується до п'яти рядків, два з яких рівно зв'язані за результатом. Чи можуть два рядки коли-небудь отримати той же номер рядка?",
          "options": [
            {
              "icon": "",
              "label": "Так — зв'язані рядки завжди ділять той же номер рядка"
            },
            {
              "icon": "",
              "label": "Тільки якщо PARTITION BY також використовується"
            },
            {
              "icon": "",
              "label": "Залежить від того, чи зв'язування в першій або останній позиції"
            },
            {
              "icon": "",
              "label": "Ні — ROW_NUMBER() завжди присвоює унікальне, суворо зростаюче ціле число кожному рядку, навіть коли значення зв'язані"
            }
          ]
        },
        {
          "question": "WITH high_earners AS (SELECT * FROM employees WHERE salary > 100000) SELECT department, COUNT(*) FROM high_earners GROUP BY department. Що таке high_earners?",
          "options": [
            {
              "icon": "",
              "label": "Спільний табличний вираз (CTE) — названий, тимчасовий набір результатів, на який може посилатися решта запиту як на таблицю"
            },
            {
              "icon": "",
              "label": "Постійна таблиця, створена в БД"
            },
            {
              "icon": "",
              "label": "Подання, яке зберігається після завершення запиту"
            },
            {
              "icon": "",
              "label": "Збережена процедура, яку необхідно викликати окремо"
            }
          ]
        },
        {
          "question": "Стовпець оголошений PRIMARY KEY. Чи можете ви вставити рядок, де той стовпець NULL?",
          "options": [
            {
              "icon": "",
              "label": "Так — PRIMARY KEY тільки забезпечує унікальність, не NULL-ність"
            },
            {
              "icon": "",
              "label": "Так, але тільки один NULL-рядок допускається, як UNIQUE-обмеження"
            },
            {
              "icon": "",
              "label": "Ні — стовпець PRIMARY KEY неявно NOT NULL, тож вставка NULL в нього відхиляється"
            },
            {
              "icon": "",
              "label": "Залежить від того, чи стовпець також має default-значення"
            }
          ]
        },
        {
          "question": "Всередину відкритої транзакції ви запускаєте UPDATE, але ще не запустили COMMIT. З другого, окремого з'єднання з БД, чи видне це оновлення?",
          "options": [
            {
              "icon": "",
              "label": "Так — всі з'єднання видять кожен запис в момент його запуску"
            },
            {
              "icon": "",
              "label": "Так, але тільки якщо друге з'єднання також відкриває транзакцію"
            },
            {
              "icon": "",
              "label": "Залежить тільки від того, яка таблиця була оновлена"
            },
            {
              "icon": "",
              "label": "Ні — незакомітована зміна видна тільки всередину транзакції, яка її зробила, доки COMMIT не зробить її довговічною та видимою для інших"
            }
          ]
        },
        {
          "question": "products.category_id має FOREIGN KEY-обмеження, яке посилається на categories.id. Ви намагаєтесь DELETE-нути рядок з categories, на який все ще вказують products, без вказаного ON DELETE-правила. Що відбувається?",
          "options": [
            {
              "icon": "",
              "label": "Рядок category видаляється, і відповідні значення products.category_id автоматично встановлюються на NULL"
            },
            {
              "icon": "",
              "label": "Рядок category видаляється, і кожен product, який на нього вказував, видаляється теж"
            },
            {
              "icon": "",
              "label": "DELETE відхиляється — стандартна поведінка зовнішнього ключа блокує видалення рядка, на який посилаються, поки залежні рядки все ще на нього вказують"
            },
            {
              "icon": "",
              "label": "DELETE успішно завершується тихо, залишаючи products' category_id вказуючим на category, яка більше не існує"
            }
          ]
        }
      ],
      "optionOrderVersion": "e0466e547cfd8a45"
    }
  }
}
