Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rewrite SQL query with JOINS in JPA

I have this SQL query for MariaDB.

select @ref:=id as id, unique_id, reference_id
from mytable
join (select @ref:=id from mytable WHERE unique_id = 55544)tmp
where reference_id=@ref

https://www.db-fiddle.com/f/jKJodfVfvw65aMaVDyFySd/0

How this query can be implemented in HQL query? I would like to use it in JPA?

like image 537
Peter Penzov Avatar asked Jan 30 '19 11:01

Peter Penzov


People also ask

Can we write SQL query in JPA?

It supports both JPQL and SQL queries, and the query that is specified by using the @Query annotation precedes all other query generation strategies. Let's find out how we can create both JPQL and SQL queries with the @Query annotation.

What does native query true mean?

NativeQuery. Native query refers to actual sql queries (referring to actual database objects). These queries are the sql statements which can be directly executed in database using a database client.

How execute native SQL query in Spring Data JPA?

In order to define SQL to execute for a Spring Data repository method, we can annotate the method with the @Query annotation — its value attribute contains the JPQL or SQL to execute. The @Query annotation takes precedence over named queries, which are annotated with @NamedQuery or defined in an orm. xml file.


2 Answers

(Answer largely re-written after comments below)

JPA doesn't have built-in support for hierarchical queries. The main option is a native query.

E.g. with this entity class:

@Entity
public class MyTable {
    @Id
    @GeneratedValue
    private int id;

    private int uniqueId;

    @ManyToOne
    private MyTable reference;

    // ... getters and setters ...
}

The following is an example of a native hierachical SQL query (actually against MySQL, just in case):

    Query query = entityManager.createNativeQuery(
            "select @ref\\:=id as id, unique_id, reference_id\r\n" +
                    "from my_table\r\n" +
                    "join (select @ref\\:=?)tmp\r\n" +
                    "where reference_id=@ref",
            MyTable.class);
    query.setParameter(1, 1);
    query.getResultList();

This was chasing down a chain of references successfully.

(Other alternatives)

There probably aren't too many other options that can do this as a single query. If scalability is less of a concern, adding a back reference would be a simple way to navigate the model:

    @OneToMany(mappedBy = "reference")
    private Set<MyTable> backReferences;

Those would then be straightforward to recursively navigate. Clearly the relation defaults to lazy loading, so would add little overhead until used.

like image 146
df778899 Avatar answered Sep 30 '22 03:09

df778899


With @df778899's MyTable in spring-data it could look like:

@Repository
public interface MyRepository extends ...

   @Query("select @ref:=id as id, unique_id, reference_id "+
           "from mytable join (select @ref:=id from mytable WHERE unique_id = :pUid) tmp "+
           "where reference_id=@ref", //just copy paste the query, use :pUid instead of constant...
            nativeQuery = true) // and this!
   List<MyTable> myCustomHirachicalQuery(@Param("pUid") Integer uid/*String/Long/...*/);
...
like image 30
xerx593 Avatar answered Sep 30 '22 04:09

xerx593