Умеешь ли писать сырые SQL-запросы и когда это необходимо?

Ответ

Да, умею и регулярно пишу raw SQL-запросы, когда того требует задача. В PHP для этого использую в основном PDO как наиболее универсальный и безопасный способ.

Когда raw SQL необходим или предпочтителен:

  1. Сложные аналитические запросы: WITH (CTE), оконные функции, сложные JOIN и агрегации, которые ORM (например, Eloquent) может выразить неэффективно или вообще не может.
    // Пример: Ранжирование заказов по сумме для каждого клиента
    $sql = "
        SELECT 
            customer_id,
            order_id,
            total_amount,
            RANK() OVER (PARTITION BY customer_id ORDER BY total_amount DESC) as rank_in_customer
        FROM orders
        WHERE status = 'completed'
    ";
    $stmt = $pdo->query($sql);
    $report = $stmt->fetchAll(PDO::FETCH_ASSOC);
  2. Миграции и работы со схемой БД: Создание индексов, изменение типов колонок, оптимизационные правки.
    // В миграции Laravel
    DB::statement('CREATE INDEX idx_user_email_active ON users (email) WHERE deleted_at IS NULL');
  3. Массовые операции (Bulk operations): INSERT ... ON DUPLICATE KEY UPDATE или COPY в PostgreSQL для загрузки больших объемов данных, что значительно быстрее постраничного сохранения через ORM.

Безопасный подход с PDO (обязательный):

// 1. Подготовленный запрос с именованными плейсхолдерами - защита от SQL-инъекций
$sql = "
    UPDATE products 
    SET price = :price, updated_at = NOW() 
    WHERE category_id = :category_id AND stock > 0
";
$stmt = $pdo->prepare($sql);

// 2. Явная привязка значений с указанием типа
$stmt->bindValue(':price', 99.99, PDO::PARAM_STR);
$stmt->bindValue(':category_id', 5, PDO::PARAM_INT);

// 3. Выполнение
$stmt->execute();

// 4. Обработка ошибок
if (!$stmt) {
    $errorInfo = $pdo->errorInfo();
    throw new RuntimeException("SQL Error: {$errorInfo[2]}");
}

Когда НЕ стоит писать raw SQL:

  • Для простых CRUD-операций (создание, чтение одной сущности) — ORM читабельнее и быстрее в разработке.
  • Если запрос можно выразить через Query Builder (например, Laravel's DB::table()) — он часто безопаснее и поддерживает разную СУБД.

Мое правило: Использую ORM для рутинных операций с данными, но без колебаний перехожу на тщательно написанный и протестированный raw SQL для сложной логики выборки, отчетности или оптимизации производительности.

Ответ 18+ 🔞

О, смотри-ка, какой серьёзный вопрос подъехал. Ну что ж, давай разложим по полочкам, как есть, без этих ваших ORM-прослоек, которые иногда только мозги выносят.

Да, конечно, умею и пишу на чистом SQL, когда ситуация того требует. В PHP мой верный друг в этом деле — PDO. Безопасно, универсально, и не надо изобретать велосипед, ёпта.

Вот тебе ситуации, когда голый SQL — это единственный правильный путь, иначе просто пиздец:

  1. Сложные отчёты и аналитика: Когда нужно ворочать WITH (эти самые CTE), оконные функции, дикие цепочки JOIN — тут ORM типа Eloquent просто сдаётся и начинает генерировать такой монструозный запрос, что глянешь на него и сам от себя охуеешь. Проще написать руками.
    // Допустим, нужно проранжировать заказы по сумме для каждого клиента
    $sql = "
        SELECT 
            customer_id,
            order_id,
            total_amount,
            RANK() OVER (PARTITION BY customer_id ORDER BY total_amount DESC) as rank_in_customer
        FROM orders
        WHERE status = 'completed'
    ";
    $stmt = $pdo->query($sql);
    $report = $stmt->fetchAll(PDO::FETCH_ASSOC);
  2. Работа со структурой базы: Создание хитрых индексов, изменение типов полей, всякие оптимизации. В миграциях Laravel, например, DB::statement() — твой лучший друг.
    // В миграции
    DB::statement('CREATE INDEX idx_user_email_active ON users (email) WHERE deleted_at IS NULL');
  3. Массовые вставки или обновления: Когда нужно залить или обновить овердохуища записей. INSERT ... ON DUPLICATE KEY UPDATE или тот же COPY в PostgreSQL сделают это в разы быстрее, чем ты будешь в цикле плодить модели и их сохранять. ORM тут просто сдохнет под нагрузкой.

Но, чувак, главное правило — безопасность, ёбаный в рот! Никаких подстав переменных напрямую в строку, иначе будет тебе хиросима и нагасаки в одном флаконе. Только подготовленные выражения:

// 1. Готовим запрос с плейсхолдерами. Это наше всё против SQL-инъекций.
$sql = "
    UPDATE products 
    SET price = :price, updated_at = NOW() 
    WHERE category_id = :category_id AND stock > 0
";
$stmt = $pdo->prepare($sql);

// 2. Жёстко привязываем значения, указывая тип. Никаких "авось проскочит".
$stmt->bindValue(':price', 99.99, PDO::PARAM_STR);
$stmt->bindValue(':category_id', 5, PDO::PARAM_INT);

// 3. Поехали.
$stmt->execute();

// 4. Всегда смотрим, что пошло не так, если что.
if (!$stmt) {
    $errorInfo = $pdo->errorInfo();
    throw new RuntimeException("SQL Error: {$errorInfo[2]}"); // Лучше своё исключение, конечно
}

А когда НЕ надо лезть с raw SQL?

  • Для элементарных действий: достать запись по ID, сохранить, удалить. ORM сделает это в одну строчку, и не надо городить.
  • Если задачу можно решить через Query Builder (тот же DB::table() в Laravel). Он часто и безопаснее, и абстрагирует тебя от особенностей конкретной СУБД. Зачем напрягать мозг, если можно не напрягать?

Итог моей философии простой, как три копейки: Для рутины — ORM, для скорости разработки. Для сложной логики, отчётов или когда производительность падает ниже плинтуса — сажусь и пишу чистый, отлаженный SQL. Главное — не превращаться в того распиздая, который всё подряд пишет голыми запросами, а потом неделю ищет, почему всё сломалось после обновления. Чувствуешь грань?