Sql

SELECT запити - Основи

Детальна анатомія SELECT запитів - вибірка даних, фільтрація WHERE, сортування ORDER BY, обмеження результатів TOP/DISTINCT

SELECT запити - Основи

Проблема: Як отримати дані з бази?

Ви створили таблицю Students, заповнили її даними. Але як тепер витягнути (retrieve) ці дані? Як знайти конкретного студента? Як відсортувати список за прізвищем?

Loading diagram...
flowchart LR
    User[Користувач] -->|Запит SQL| DB[(База Даних)]
    DB -->|Результат| ResultSet[Result Set<br/>Віртуальна таблиця]
    ResultSet --> User

    style DB fill:#3b82f6,color:#fff
    style ResultSet fill:#10b981,color:#fff

SELECT — це найважлив найважливіша команда в SQL, яка дозволяє читати дані з таблиць.

Статистика: В реальних проектах близько 90% всіх SQL-запитів — це SELECT. Тому дуже важливо розуміти його детально!

Чому SELECT - це DML, а не DDL?

Пригадаймо різницю:

Робота зі структурою БД:

  • CREATE TABLE
  • ALTER TABLE
  • DROP TABLE

НЕ працює з даними всередині таблиць

SELECT відноситься до DML, оскільки працює з даними, а не зі structure.


Фундаментальні концепції

Декларативна природа SQL

SQL — це декларативна мова програмування. Ви описуєте ЩО потрібно отримати, а не ЯК це зробити.

// Ви описуєте КРОКИ
1. Відкрити таблицю Students
2. Пройтися по кожному рядку
3. Для кожного рядка перевірити: Age > 20?
4. Якщо так - додати до результату
5. Повернути результат

Result Set: Віртуальна таблиця

Результат SELECT — це result set (набір результатів) — віртуальна таблиця в пам'яті:

SELECT FirstName, LastName FROM Students;

Result Set:

FirstNameLastName
ІванПетренко
МаріяКоваленко
......
Ключова відмінність: Result Set існує тільки на час виконання запиту. Це НЕ реальна таблиця в БД!

Порядок логічного виконання

SQL запит виконується НЕ в тому порядку, в якому ви його пишете!

Loading diagram...
@startuml
skinparam style plain
skinparam defaultFontName "Segoe UI"

rectangle "SELECT FirstName, LastName\n(3. Потім вибір стовпців)" as SELECT #LightBlue
rectangle "FROM Students\n(1. Спочатку джерело)" as FROM #LightGreen
rectangle "WHERE Age > 20\n(2. Потім фільтрація)" as WHERE #LightCoral
rectangle "ORDER BY LastName\n(4. Нарешті сортування)" as ORDER #LightGoldenRodYellow

FROM -down-> WHERE
WHERE -down-> SELECT
SELECT -down-> ORDER
@enduml

Логічний порядок виконання:

  1. FROM — визначити джерело даних (таблицю)
  2. WHERE — відфільтрувати рядки
  3. SELECT — вибрати стовпці
  4. ORDER BY — відсортувати результат
Важливо: Це логічний порядок обробки запиту SQL Server. Фізичний порядок може відрізнятися через оптимізацію.

Базовий синтаксис SELECT

Мінімальний запит

SELECT * FROM Students;

Анатомія:

  • SELECT — ключове слово команди
  • * — вибрати всі стовпці
  • FROM Students — з таблиці Students

Результат: Всі рядки і всі стовпці таблиці Students.

SELECT конкретних стовпців

SELECT FirstName, LastName FROM Students;

Результат: Тільки два стовпці (FirstName, LastName) для всіх студентів.

Best Practice: Уникайте SELECT * в production коді:
  • Повертає зайві дані (погіршує performance)
  • Код стає менш читабельним
  • Зміни в структурі таблиці можуть зламати код
Виняток: SELECT * прийнятний для швидкого тестування/дебагу.

Порядок стовпців

Порядок стовпців в SELECT визначає порядок в result set:

SELECT LastName, FirstName, BirthDate FROM Students;

Result Set:

LastNameFirstNameBirthDate
ПетренкоІван1998-03-15
.........

Псевдоніми (AS - Aliases)

Псевдоніми дозволяють перейменувати стовпці або таблиці в result set.

Псевдоніми для стовпців

SELECT
    FirstName AS "Ім'я",
    LastName AS Прізвище,
    BirthDate AS ДатаНародження
FROM Students;

Result Set:

Ім'яПрізвищеДатаНародження
ІванПетренко1998-03-15
.........

Варіанти синтаксису:

SELECT FirstName AS Name FROM Students;
Використовуйте квадратні дужки [] для псевдонімів з пробілами або спецсимволамиімів з пробілами.

Псевдоніми для таблиць

Корисно для коротких назв або при JOIN (який розглянемо пізніше):

SELECT s.FirstName, s.LastName
FROM Students AS s;
--             ^^^^
--             Псевдонім таблиці

Конкатенація та арифметичні операції

Конкатенація рядків

Об'єднання текстових полів в одне:

SELECT
    FirstName + ' ' + LastName AS FullName
FROM Students;

Result Set:

FullName
Іван Петренко
Марія Коваленко
...

Приклад з форматуванням:

SELECT
    'Student: ' + LastName + ', ' + FirstName + ' (ID: ' + CAST(Id AS NVARCHAR) + ')' AS StudentInfo
FROM Students;

Result Set:

Student: Петренко, Іван (ID: 1)
Student: Коваленко, Марія (ID: 2)
Проблема з NULL: Якщо хоча б одне поле NULL, результат конкатенації буде NULL!
SELECT 'Email: ' + Email FROM Students WHERE Id = 4;
-- Email поле може бути NULL
-- Результат: NULL (не "Email: NULL")
Розв'язок: Використовуйте ISNULL() або COALESCE():
SELECT 'Email: ' + ISNULL(Email, 'Not provided') FROM Students;

Арифметичні операції

SELECT
    Grants,
    Grants * 1.1 AS GrantsWithIncrease,
    Grants * 12 AS YearlyGrants
FROM Students
WHERE Grants IS NOT NULL;

Result Set:

GrantsGrantsWithIncreaseYearlyGrants
1200.001320.0014400.00
1500.001650.0018000.00

Доступні оператори:

  • + — додавання
  • - — віднімання
  • * — множення
  • / — ділення
  • % — остача від ділення (modulo)

Функції перетворення: CAST та CONVERT

Інодіколи потрібно перетворити один тип даних в інший.

CAST Function

Стандартний SQL спосіб (рекомендовано):

SELECT
    Id,
    CAST(Id AS NVARCHAR(10)) AS IdAsString,
    CAST(Grants AS INT) AS GrantsRounded
FROM Students;

Синтаксис: CAST(expression AS data_type)

CONVERT Function

T-SQL специфічний спосіб з додатковими можливостями форматування:

SELECT
    BirthDate,
    CONVERT(NVARCHAR, BirthDate, 104) AS DateGerman,  -- DD.MM.YYYY
    CONVERT(NVARCHAR, BirthDate, 103) AS DateBritish, -- DD/MM/YYYY
    CONVERT(NVARCHAR, BirthDate, 101) AS DateUSA      -- MM/DD/YYYY
FROM Students;

Result Set:

BirthDateDateGermanDateBritishDateUSA
1998-03-1515.03.199815/03/199803/15/1998

Синтаксис: CONVERT(data_type, expression, style)

Коли використовувати що:
  • CAST — для простих перетворень (портабельніше)
  • CONVERT — коли потрібен специфічний формат дат

Приклади перетворення

SELECT CAST(1234 AS NVARCHAR) AS NumberAsString;
-- Результат: '1234'

WHERE: Фільтрація рядків

WHERE clause дозволяє вибрати тільки ті рядки, які задовольняють певну умову.

Базовий синтаксис

SELECT column1, column2
FROM table_name
WHERE condition;

Оператори порівняння

ОператорЗначенняПриклад
=ДорівнюєAge = 20
<> або !=Не дорівнюєAge <> 20
>БільшеAge > 20
<МеншеAge < 20
>=Більше або дорівнюєAge >= 20
<=Менше або дорівнюєAge <= 20

Приклади з WHERE

-- Студенти народжені в 1998 році
SELECT * FROM Students
WHERE YEAR(BirthDate) = 1998;

-- Студенти зі стипендією більше 1400
SELECT FirstName, LastName, Grants
FROM Students
WHERE Grants > 1400;

-- Конкретний студент за прізвищем
SELECT * FROM Students
WHERE LastName = 'Петренко';
Регістр та порівняння рядків:
  • В SQL Server порівняння рядків за замовчуванням case-insensitive (не враховує регістр):
WHERE LastName = 'петренко'  -- Знайде "Петренко", "петренко", "ПЕТРЕНКО"
Для case-sensitive порівняння використовуйте COLLATE:
WHERE LastName COLLATE Latin1_General_CS_AS = 'Петренко'

Логічні оператори: AND, OR, NOT

Комбінуйте кілька умов за допомогою логічних операторів.

AND (І) - Обидві умови мають бути TRUE

-- Студенти народжені в 1998 році ЗІ стипендією
SELECT * FROM Students
WHERE YEAR(BirthDate) = 1998 AND Grants IS NOT NULL;

OR (АБО) - Хоча б одна умова TRUE

-- Студенти народжені в 1997 АБО 1999 році
SELECT * FROM Students
WHERE YEAR(BirthDate) = 1997 OR YEAR(BirthDate) = 1999;

NOT (НЕ) - Інверсія умови

-- Студенти НЕ народжені в 1998 році
SELECT * FROM Students
WHERE NOT YEAR(BirthDate) = 1998;

-- Еквівалентно:
WHERE YEAR(BirthDate) <> 1998;

Пріоритет операторів

Порядок виконання (від вищого до нижчого):

  1. NOT
  2. AND
  3. OR

Приклад:

-- Хто народився в 1998 ЗІ стипендією > 1300 АБО будь-хто з 1997
SELECT * FROM Students
WHERE YEAR(BirthDate) = 1998 AND Grants > 1300 OR YEAR(BirthDate) = 1997;

-- Логіка: (1998 AND Grants>1300) OR (1997)
--         ^^^^^^^^^^^^^^^^^^^^^^     ^^^^^
--               Група 1             Група 2

Використання дужок для clarity

Завжди використовуйте дужки для складних умов:

SELECT * FROM Students
WHERE (YEAR(BirthDate) = 1998 AND Grants > 1300)
   OR YEAR(BirthDate) = 1997;

Складний приклад:

-- Студенти які:
-- - Народилися в 1997-1998 І мають стипендію > 1400
-- АБО
-- - Народилися в 1999 І НЕ мають Email
SELECT * FROM Students
WHERE (
        (YEAR(BirthDate) IN (1997, 1998) AND Grants > 1400)
        OR
        (YEAR(BirthDate) = 1999 AND Email IS NULL)
      );

NULL значення: IS NULL та IS NOT NULL

NULL — це спеціальне значення "невідомо" або "відсутнє". Робота з NULL має свої особливості.

Перевірка на NULL

НЕПРАВИЛЬНО:
SELECT * FROM Students WHERE Email = NULL;   -- ❌ Поверне 0 рядків!
SELECT * FROM Students WHERE Email <> NULL;  -- ❌ Також 0 рядків!
Причина: NULL не дорівнює нічому, навіть іншому NULL. Будь-яке порівняння з NULL дає UNKNOWN (не TRUE, не FALSE).

ПРАВИЛЬНО:

-- Студенти БЕЗ Email
SELECT * FROM Students
WHERE Email IS NULL;

-- Студенти З Email
SELECT * FROM Students
WHERE Email IS NOT NULL;

NULL в арифметиці

Будь-яка операція з NULL дає NULL:

SELECT
    Grants,
    Grants + 100 AS GrantsPlusBonus
FROM Students;

-- Якщо Grants = NULL, то GrantsPlusBonus = NULL (не 100!)

Розв'язок: Використовуйте ISNULL() або COALESCE():

SELECT
    Grants,
    ISNULL(Grants, 0) + 100 AS GrantsPlusBonus
FROM Students;
-- Якщо Grants = NULL, то ISNULL поверне 0, результат: 0 + 100 = 100

ORDER BY: Сортування результатів

ORDER BY дозволяє відсортувати result set за одним або кількома стовпцями.

Базовий синтаксис

SELECT columns
FROM table
ORDER BY column1 [ASC | DESC], column2 [ASC | DESC];
  • ASC (Ascending) — за зростанням (за замовчуванням)
  • DESC (Descending) — за спаданням

Приклади

SELECT FirstName, LastName
FROM Students
ORDER BY LastName ASC;  -- ASC можна не писати (за замовчуванням)

NULL значення в сортуванні

В SQL Server NULL values сортуються першими при ASC і останніми при DESC:

SELECT FirstName, Email
FROM Students
ORDER BY Email ASC;

-- Порядок результату:
-- 1. Студенти з Email = NULL (спочатку)
-- 2. Студенти з Email (відсортовані А→Я)

Сортування за номером стовпця

Можна вказувати номер стовпця замість назви:

SELECT FirstName, LastName, BirthDate
FROM Students
ORDER BY 2, 1;  -- 2 = LastName, 1 = FirstName
Не рекомендовано: Код стає менш читабельним. Використовуйте тільки в інтерактивних запитах, не в production коді.

TOP: Обмеження кількості результатів

TOP дозволяє вибрати перші N рядків з result set.

Базовий синтаксис

SELECT TOP (n) columns
FROM table
[ORDER BY column];

Приклади

-- 5 найстаріших студентів
SELECT TOP (5) FirstName, LastName, BirthDate
FROM Students
ORDER BY BirthDate ASC;

-- 3 студенти з найбільшою стипендією
SELECT TOP (3) FirstName, Grants
FROM Students
ORDER BY Grants DESC;
Без ORDER BY — результат непередбачуваний!
SELECT TOP (5) * FROM Students;
-- Поверне 5 рядків, але НЕПЕРЕДБАЧУВАНО які саме
Завжди використовуйте TOP з ORDER BY для передбачуваних результатів!

TOP з відсотками (PERCENT)

-- 10% студентів з найвищою стипендією
SELECT TOP (10) PERCENT FirstName, Grants
FROM Students
ORDER BY Grants DESC;

TOP WITH TIES

Включити всі рядки з однаковим значенням останнього рядка:

-- Топ 3, але включити всіх з однаковою стипендією
SELECT TOP (3) WITH TIES FirstName, Grants
FROM Students
ORDER BY Grants DESC;

Якщо 3-й та 4-й студенти мають однакову стипендію, обидва будуть включені:

FirstNameGrantsСтатус
Дмитро1800.00Попадає в TOP 3
Максим1750.00Попадає в TOP 3
Катерина1650.00Останній в рядок TOP 3
Вікторія1650.00← WITH TIES включає цей рядок

DISTINCT: Видалення дублікатів

DISTINCT видаляє дублікати з result set.

Базовий синтаксис

SELECT DISTINCT column1, column2
FROM table;

Приклади

-- Унікальні роки народження
SELECT DISTINCT YEAR(BirthDate) AS BirthYear
FROM Students
ORDER BY BirthYear;

-- Результат: 1997, 1998, 1999 (без повторень)

Без DISTINCT:

SELECT YEAR(BirthDate) AS BirthYear
FROM Students;

-- Результат: 1998, 1997, 1999, 1998, 1997, 1998, 1999... (з повтореннями)

DISTINCT на кількох стовпцях

DISTINCT працює на комбінації всіх вказаних стовпців:

SELECT DISTINCT LastName, FirstName
FROM Students;

-- Унікальні комбінації (LastName, FirstName)

COUNT з DISTINCT

Підрахунок унікальних значень:

-- Скільки різних років народження?
SELECT COUNT(DISTINCT YEAR(BirthDate)) AS UniqueYears
FROM Students;

-- Результат: 3 (1997, 1998, 1999)
Performance note: DISTINCT може бути вимогливим до ресурсів на великих таблицях. Використовуйте тільки коли дійсно потрібно.

Практичні приклади

Приклад 1: Список студентів зі стипендією, відсортований

SELECT
    LastName + ' ' + FirstName AS FullName,
    Grants AS GrantAmount,
    Grants * 12 AS YearlyAmount
FROM Students
WHERE Grants IS NOT NULL
ORDER BY Grants DESC;

Приклад 2: Студенти без Email

SELECT
    Id,
    FirstName,
    LastName,
    'No email provided' AS EmailStatus
FROM Students
WHERE Email IS NULL;

Приклад 3: Топ 5 наймолодших студентів

SELECT TOP (5)
    FirstName,
    LastName,
    BirthDate,
    YEAR(GETDATE()) - YEAR(BirthDate) AS ApproximateAge
FROM Students
ORDER BY BirthDate DESC;

Приклад 4: Унікальні місяці народження

SELECT DISTINCT
    MONTH(BirthDate) AS BirthMonth,
    DATENAME(MONTH, BirthDate) AS MonthName
FROM Students
ORDER BY BirthMonth;

Практичні завдання


Резюме

Ключові моменти SELECT запитів:
  1. SELECT — найважливіша DML команда для читання даних
  2. Логічний порядок: FROM → WHERE → SELECT → ORDER BY
  3. SELECT vs SELECT *: Завжди вказуйте конкретні стовпці в production
  4. Псевдоніми (AS): Роблять код читабельнішим
  5. Конкатенація (+): Об'єднання рядків (увага на NULL!)
  6. CAST/CONVERT: Перетворення типів даних
  7. WHERE: Фільтрація рядків (=, <>, >, <, >=, <=)
  8. AND/OR/NOT: Логічні оператори для складних умов
  9. IS NULL / IS NOT NULL: Єдиний правильний спосіб перевірки NULL
  10. ORDER BY: Сортування (ASC/DESC), завжди з TOP!
  11. TOP: Обмеження результатів (n рядків або PERCENT)
  12. DISTINCT: Видалення дублікатів
Наступний крок: Вивчіть розширені можливості SELECT (IN, BETWEEN, LIKE, функції дат/рядків).

ВправиВправи

Copyright © 2026