Комментарии (2)
🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Синтаксис SQL-запроса: от базовой структуры до особенностей Go
SQL (Structured Query Language) имеет **декларативный синтаксис**, где вы описываете *что* нужно получить, а не *как*. Основная структура большинства запросов строится вокруг ключевого слова **SELECT**, но полный синтаксис включает множество компонентов.
Базовый синтаксис SELECT-запроса
SELECT [DISTINCT] column1, column2, ...
FROM table_name
[WHERE condition]
[GROUP BY column1, column2, ...]
[HAVING group_condition]
[ORDER BY column1 [ASC|DESC], ...]
[LIMIT count];
Пример простейшего запроса:
SELECT id, name, email FROM users WHERE active = 1 ORDER BY created_at DESC LIMIT 10;
Ключевые компоненты SQL-синтаксиса
1. Клаузы (Clauses)
- SELECT - указывает возвращаемые столбцы (можно использовать
*для всех) - FROM - определяет таблицу(ы) для запроса
- WHERE - фильтрует строки по условию
- JOIN - объединяет таблицы (INNER, LEFT, RIGHT, FULL)
- GROUP BY - группирует строки для агрегатных функций
- HAVING - фильтрует сгруппированные данные
- ORDER BY - сортирует результаты
- LIMIT/OFFSET - ограничивает количество результатов
2. Агрегатные функции
SELECT
COUNT(*) as total,
AVG(salary) as avg_salary,
MAX(age) as max_age,
SUM(price) as total_price
FROM employees;
3. JOIN-операции
-- INNER JOIN (только совпадающие строки)
SELECT u.name, o.order_date, o.amount
FROM users u
INNER JOIN orders o ON u.id = o.user_id;
-- LEFT JOIN (все строки из левой таблицы)
SELECT u.name, o.order_date
FROM users u
LEFT JOIN orders o ON u.id = o.user_id;
4. Подзапросы (Subqueries)
SELECT name, email
FROM users
WHERE id IN (SELECT user_id FROM orders WHERE amount > 1000);
-- Коррелированный подзапрос
SELECT name, (SELECT COUNT(*) FROM orders WHERE user_id = users.id) as order_count
FROM users;
Особенности SQL в контексте Go
В Go работа с SQL имеет свою специфику:
Использование плейсхолдеров для безопасности
// НЕПРАВИЛЬНО - уязвимо для SQL-инъекций
query := fmt.Sprintf("SELECT * FROM users WHERE name = '%s'", userName)
// ПРАВИЛЬНО - используем плейсхолдеры
query := "SELECT id, name, email FROM users WHERE active = ? AND age > ?"
rows, err := db.Query(query, true, 18)
Поддержка разных диалектов SQL
// PostgreSQL (использует $1, $2...)
query := "SELECT * FROM users WHERE id = $1 AND status = $2"
// MySQL/SQLite (использует ?)
query := "SELECT * FROM users WHERE id = ? AND status = ?"
// Именованные параметры (через sqlx)
query := "SELECT * FROM users WHERE name = :name AND age > :min_age"
Конструкция запросов динамически
func buildUserQuery(active *bool, minAge *int) (string, []interface{}) {
var whereClauses []string
var args []interface{}
var argPos = 1
if active != nil {
whereClauses = append(whereClauses, fmt.Sprintf("active = $%d", argPos))
args = append(args, *active)
argPos++
}
if minAge != nil {
whereClauses = append(whereClauses, fmt.Sprintf("age >= $%d", argPos))
args = append(args, *minAge)
argPos++
}
query := "SELECT * FROM users"
if len(whereClauses) > 0 {
query += " WHERE " + strings.Join(whereClauses, " AND ")
}
return query, args
}
Расширенные возможности SQL-синтаксиса
CTE (Common Table Expressions)
WITH active_users AS (
SELECT id, name, email
FROM users
WHERE last_login > NOW() - INTERVAL '30 days'
),
user_orders AS (
SELECT user_id, COUNT(*) as order_count
FROM orders
GROUP BY user_id
)
SELECT au.name, au.email, uo.order_count
FROM active_users au
LEFT JOIN user_orders uo ON au.id = uo.user_id;
Оконные функции (Window Functions)
SELECT
name,
department,
salary,
AVG(salary) OVER (PARTITION BY department) as avg_department_salary,
RANK() OVER (PARTITION BY department ORDER BY salary DESC) as rank_in_department
FROM employees;
Важные нюансы SQL для Go-разработчиков
-
Экранирование идентификаторов - используйте двойные кавычки или бэктики в зависимости от СУБД
-
Типы данных - соответствие между SQL-типами и Go-типами
-
NULL-обработка - используйте
sql.NullString,sql.NullInt64и т.д. -
Транзакции - группировка запросов в транзакции для atomicity
tx, err := db.Begin() _, err = tx.Exec("UPDATE accounts SET balance = balance - ? WHERE id = ?", amount, fromID) _, err = tx.Exec("UPDATE accounts SET balance = balance + ? WHERE id = ?", amount, toID) err = tx.Commit() -
Подготовленные выражения (Prepared Statements) для повторяющихся запросов:
stmt, err := db.Prepare("SELECT * FROM users WHERE id = ?") defer stmt.Close() // Многократное использование stmt.Query(1) stmt.Query(2)
SQL-синтаксис может варьироваться между разными СУБД (PostgreSQL, MySQL, SQLite), но основные принципы остаются общими. В Go критически важно правильно обрабатывать параметры запросов для предотвращения инъекций и учитывать особенности конкретного драйвера базы данных.