Как использовать результат SELECT в операторе UPDATE в SQL?

Ответ

Результат подзапроса SELECT можно использовать в UPDATE для определения обновляемых строк или вычисления новых значений. Это делается через подзапросы в условии WHERE или в выражении SET.

1. Подзапрос в условии WHERE (самый частый случай): Обновить записи на основе данных из другой таблицы.

-- Повысить зарплату сотрудникам IT-департамента
UPDATE employee e
SET e.salary = e.salary * 1.15
WHERE e.department_id IN (
    SELECT d.id
    FROM department d
    WHERE d.name = 'IT'
);
-- Использование JOIN в UPDATE (более эффективно в некоторых СУБД)
UPDATE employee e
JOIN department d ON e.department_id = d.id
SET e.salary = e.salary * 1.15
WHERE d.name = 'IT';

2. Подзапрос в выражении SET: Установить значение на основе агрегации или выборки из другой таблицы.

-- Установить цену товара как среднюю цену по категории
UPDATE product p
SET p.price = (
    SELECT AVG(price)
    FROM product p2
    WHERE p2.category_id = p.category_id
)
WHERE p.category_id = 5;

Важные замечания и best practices:

  • Производительность: Подзапросы, особенно коррелированные (ссылающиеся на внешнюю таблицу), могут быть медленными на больших объемах данных. Всегда проверяйте EXPLAIN план.
  • Читаемость: Для сложных условий часто лучше использовать UPDATE ... FROM ... JOIN (синтаксис зависит от СУБД: PostgreSQL, MySQL 8.0+, SQL Server поддерживают JOIN).
  • В JPA/Hibernate: Прямые DML-операции UPDATE с подзапросами выполняются через нативные запросы (@Query с nativeQuery = true) или критерии. HQL/JPQL поддерживает подзапросы в WHERE, но не в SET для DML.
    @Repository
    public interface EmployeeRepository extends JpaRepository<Employee, Long> {
        @Modifying
        @Query(value = "UPDATE employee e SET e.salary = e.salary * 1.1 " +
                       "WHERE e.department_id IN (SELECT d.id FROM department d WHERE d.name = :deptName)",
               nativeQuery = true)
        int giveRaiseToDepartment(@Param("deptName") String deptName);
    }

Ответ 18+ 🔞

Да ты посмотри, какая, блядь, интересная штука! Результат этого самого SELECT можно, сука, впихнуть прямо в UPDATE, чтобы понять, какие строки трогать или новые значения посчитать. Вообще, это через подзапросы в WHERE или в самом SET делается.

1. Подзапрос в WHERE (самое, блядь, частое применение): Тут мы обновляем записи, отталкиваясь от данных из другой таблицы. Представь, как начальник отделу IT зарплату поднимает.

-- Повысить зарплату сотрудникам IT-департамента
UPDATE employee e
SET e.salary = e.salary * 1.15
WHERE e.department_id IN (
    SELECT d.id
    FROM department d
    WHERE d.name = 'IT'
);
-- А можно через JOIN в UPDATE (иногда это, блядь, шустрее)
UPDATE employee e
JOIN department d ON e.department_id = d.id
SET e.salary = e.salary * 1.15
WHERE d.name = 'IT';

2. Подзапрос прямо в SET: Тут мы значение ставим на основе какой-нибудь средней температуры по больнице из другой таблицы.

-- Сделать цену товара как среднюю по его категории
UPDATE product p
SET p.price = (
    SELECT AVG(price)
    FROM product p2
    WHERE p2.category_id = p.category_id
)
WHERE p.category_id = 5;

А теперь, блядь, важные моменты, чтобы не наебнуться:

  • Скорость: Подзапросы, особенно те, что на внешнюю таблицу ссылаются (коррелированные), могут на больших данных тормозить, как черепаха в сиропе. Всегда смотри EXPLAIN, не ленись, епта.
  • Понятность: Если условия сложные — проще часто через UPDATE ... FROM ... JOIN сделать. Но синтаксис, блядь, разный у PostgreSQL, MySQL и прочих.
  • В JPA/Hibernate: Прямые такие UPDATE с подзапросами — это удел нативных запросов (@Query с nativeQuery = true) или критериев. HQL/JPQL подзапросы в WHERE для DML ещё куда ни шло, а вот в SET — нихуя.
    @Repository
    public interface EmployeeRepository extends JpaRepository<Employee, Long> {
        @Modifying
        @Query(value = "UPDATE employee e SET e.salary = e.salary * 1.1 " +
                       "WHERE e.department_id IN (SELECT d.id FROM department d WHERE d.name = :deptName)",
               nativeQuery = true)
        int giveRaiseToDepartment(@Param("deptName") String deptName);
    }

Вот так вот, блядь. Главное — головой думай, а не просто копипасть.