Как переписать этот SQL-запрос в Java-код (например, с использованием JDBC/PreparedStatement или JPA/Hibernate)?

Есть такой SQL-запрос:
  • 13 марта 2026 г. 10:00
Ответы на вопрос 2
Похоже, вы не вставили сам SQL‑запрос. Чтобы дать точный Java‑код — лучше пришлите SQL. Ниже привожу шаблоны и примеры, как в целом переводится SQL в Java: JDBC (PreparedStatement) и JPA/Hibernate. Подставьте свои имена таблиц/полей/параметров или пришлите конкретный запрос — тогда перепишу точнее.

1) JDBC + PreparedStatement (обычный селект)
- пример: SELECT id, name, created_at FROM person WHERE status = ? AND age > ?

```java
// POJO
public class Person {
    private Long id;
    private String name;
    private LocalDateTime createdAt;
    // геттеры/сеттеры/конструкторы
}

// метод получения
public List<Person> findPersons(Connection conn, String status, int minAge) throws SQLException {
    String sql = "SELECT id, name, created_at FROM person WHERE status = ? AND age > ?";
    List<Person> result = new ArrayList<>();

    try (PreparedStatement ps = conn.prepareStatement(sql)) {
        ps.setString(1, status);
        ps.setInt(2, minAge);

        try (ResultSet rs = ps.executeQuery()) {
            while (rs.next()) {
                Person p = new Person();
                p.setId(rs.getLong("id"));
                p.setName(rs.getString("name"));
                Timestamp ts = rs.getTimestamp("created_at");
                if (ts != null) p.setCreatedAt(ts.toLocalDateTime());
                result.add(p);
            }
        }
    }
    return result;
}
```

Основные моменты:
- Используйте try-with-resources для автоматического закрытия PreparedStatement/ResultSet.
- Привязывайте параметры через ps.setXXX(index, value).
- Для INSERT/UPDATE/DELETE используйте ps.executeUpdate(); для получения сгенерированного ключа — PreparedStatement.RETURN_GENERATED_KEYS и ps.getGeneratedKeys().

2) JDBC — вставка с возвращением ключа
```java
String sql = "INSERT INTO person(name, status, age) VALUES (?, ?, ?)";
try (PreparedStatement ps = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) {
    ps.setString(1, name);
    ps.setString(2, status);
    ps.setInt(3, age);
    int affected = ps.executeUpdate();
    try (ResultSet keys = ps.getGeneratedKeys()) {
        if (keys.next()) {
            long id = keys.getLong(1);
            // ...
        }
    }
}
```

3) JPA (JPQL) — получение сущностей (EntityManager)
- допустим, у вас есть сущность Person mapped to person table.

JPQL пример:
```java
// метод в DAO/репозитории
public List<Person> findPersons(EntityManager em, String status, int minAge) {
    String jpql = "SELECT p FROM Person p WHERE p.status = :status AND p.age > :minAge";
    TypedQuery<Person> q = em.createQuery(jpql, Person.class)
                             .setParameter("status", status)
                             .setParameter("minAge", minAge);
    return q.getResultList();
}
```

Native SQL через JPA:
```java
List<Object[]> rows = em.createNativeQuery(
    "SELECT id, name, created_at FROM person WHERE status = :status AND age > :minAge")
    .setParameter("status", status)
    .setParameter("minAge", minAge)
    .getResultList();

for (Object[] row : rows) {
    Long id = ((Number)row[0]).longValue();
    String name = (String) row[1];
    Timestamp ts = (Timestamp) row[2];
    // ...
}
```

4) JPA — проекции в DTO (конструкторное выражение JPQL)
Если хотите вернуть DTO, можно использовать конструкторную проекцию (DTO должен иметь соответствующий конструктор):
```java
// DTO с конструктором: public PersonDto(Long id, String name, LocalDateTime createdAt) { ... }
String jpql = "SELECT new com.example.PersonDto(p.id, p.name, p.createdAt) FROM Person p WHERE p.status = :status";
List<PersonDto> dtos = em.createQuery(jpql, PersonDto.class)
                         .setParameter("status", status)
                         .getResultList();
```

5) Hibernate (Session) — native SQL с маппингом на сущность/скаляр
```java
Session session = sessionFactory.openSession();
NativeQuery<Person> query = session.createNativeQuery(
    "SELECT * FROM person WHERE status = :status", Person.class);
query.setParameter("status", status);
List<Person> persons = query.getResultList();
```

6) Примечания по конвертации сложных запросов
- JOIN/агрегации: JPQL умеет JOIN и GROUP BY, но синтаксис ориентирован на сущности (p.department d …). Иногда проще использовать native query и маппить в DTO вручную.
- IN‑список: для PreparedStatement нужно динамически генерировать количество ? или использовать setArray (зависит от СУБД) или использовать JPA setParameterList (в Hibernate) / setParameter с Collection в JPQL.
- Параметры даты/времени: в JDBC используйте setTimestamp/setDate; в JPA — чаще LocalDate/LocalDateTime мэпятся автоматически (зависит от JPA версии/драйвера).
- Транзакции: для изменений (INSERT/UPDATE/DELETE) используйте транзакцию (JPA — em.getTransaction().begin()/commit() или контейнерная транзакция, Spring @Transactional).

7) Пример конвертации сложного SQL (примерный)
SQL:
SELECT p.id, p.name, d.name as deptName, COUNT(t.id) taskCount
FROM person p
JOIN department d ON p.dept_id = d.id
LEFT JOIN task t ON t.person_id = p.id
WHERE p.status = ?
GROUP BY p.id, p.name, d.name
HAVING COUNT(t.id) > ?

JDBC:
- Собрать SQL, PreparedStatement, установить параметры, пройти ResultSet и заполнить DTO (в котором поля id, name, deptName, taskCount).

JPQL (если есть Entity связи):
String jpql =
"SELECT new com.example.PersonTaskDto(p.id, p.name, d.name, COUNT(t)) " +
"FROM Person p JOIN p.department d LEFT JOIN p.tasks t " +
"WHERE p.status = :status " +
"GROUP BY p.id, p.name, d.name " +
"HAVING COUNT(t) > :minTasks";

TypedQuery<PersonTaskDto> q = em.createQuery(jpql, PersonTaskDto.class)
    .setParameter("status", status)
    .setParameter("minTasks", minTasks);

Если пришлёте ваш конкретный SQL — перепишу его в JDBC/PreparedStatement и/или JPA/Hibernate с учётом ваших сущностей/DTO.
Чатжпт на удивление понял проблему и дал рабочее решение: <br/> <br/> <pre><code class="java">Join&lt;GroupEntity, GroupAttributeEntity&gt; attributesJoin =
        group.join("attributes", JoinType.LEFT);

Predicate joinCondition = cb.equal(attributesJoin.get("name"), sort);
attributesJoin.on(joinCondition);

query.groupBy(group.get("id"), attributesJoin.get("value"));

// btrim(value, 'Code-')
Expression&lt;String&gt; trimmed =
        cb.function("btrim", String.class,
                attributesJoin.get("value"),
                cb.literal("Code-"));

// cast to integer
Expression&lt;Integer&gt; sortedValue =
        cb.coalesce(trimmed.as(Integer.class), 0);

if (isDesc) {
    query.orderBy(cb.desc(sortedValue));
} else {
    query.orderBy(cb.asc(sortedValue));
}</code></pre>
Похожие вопросы