8

I'm using spring data JPA and I want to write a SQL query in my repository.

I have a following SQL query (notice the LEFT JOIN):

SELECT * FROM institution LEFT JOIN 
(select * from building_institutions where building_institutions.building_id = 1) as reserved_institutions
ON reserved_institutions.institutions_user_id = institution.user_id
WHERE reserved_institutions.institutions_user_id is null;

and i want to execute it in my InstitutionRepository which is as follows:

@Repository
public interface InstitutionRepository extends JpaRepository<Institution, Long>, PagingAndSortingRepository<Institution,Long> {
    // doesn't work
    //@Query("SELECT b.institutions as bi FROM Building b left join Institution i WHERE bi.building_id not in :id")
    Page<Institution> findPotentialInstitutionsByBuildingId(@Param("id") Collection<Long> id, Pageable pageable);

    // doesn't work    
    @Query(
            value = "SELECT * FROM kits_nwt.institution LEFT JOIN\n" +
                    "(SELECT * FROM kits_nwt.building_institutions WHERE kits_nwt.building_institutions.building_id = ?1) AS reserved_institutions\n" +
                    "ON reserved_institutions.institutions_user_id = kits_nwt.institution.user_id\n" +
                    "WHERE reserved_institutions.institutions_user_id IS null ORDER BY ?#{#pageable}",
            nativeQuery = true)
    Page<Institution> findPotentialInstitutionsByBuildingId(Long userId, Pageable pageable);
}

So, I want to get all institutions which are not in building with certain ID (which I will send as a parameter).

Here is my current DB data:

Institutions:

Institutions

Building institutions:

Building institutions

What I want: (in this query, the id is set on 1, for presentation purposes)

What I want

I have looked at many SO questions and answers (such as this one) but I haven't been able to figure out the solution.

So, how do I write this query so that I get what I want?

Edit 1:

@KevinAnderson Currently, I'm trying with:

@Query(
        value = "SELECT username, password, description, location, title, user_id FROM (institution INNER JOIN user ON institution.user_id = user.id) LEFT JOIN\n" +
                "(SELECT * FROM building_institutions WHERE building_institutions.building_id = 1) AS reserved_institutions\n" +
                "ON reserved_institutions.institutions_user_id = kits_nwt.institution.user_id\n" +
                "WHERE reserved_institutions.institutions_user_id IS null ORDER BY ?#{#pageable}",
        nativeQuery = true)
Page<Institution> findPotentialInstitutionsByBuildingId(Long userId, Pageable pageable);

And I'm getting this exception:

MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'WHERE) FROM building_institutions WHERE building_institutions.building_id = 1) A' at line 2

Edit 2:

@StanislavL here it is:

enter image description here

The problem is that your query gets me the institution with ID 25 because it is in both building with ID 1 and building with ID 2. When you do a JOIN, you have 2 rows ON institution ID being 25 in both institution table and building_institutions table. Then, your WHERE condition removes one from those two rows and I get one row where instituiton ID is 25, and I don't want what.

Here is an image for the above:

Join without WHERE

Edit 3 - this question is not a duplicate because of the following:

  • My query is with pagination (I added "with pagination" to the question title)
  • I'm not using @NamedQuery but @Query
  • My mistake was that I didn't write countQuery parameter to the @Query annotation
8
  • 1
    If you can't figure out a solution doesn't mean that it doesn't have one. Commented Jan 26, 2018 at 1:13
  • What result are you getting? Commented Jan 26, 2018 at 1:34
  • @KevinAnderson I'll edit my question with what I'm trying right now. Commented Jan 26, 2018 at 10:10
  • @RomanC I didn't say it doesn't have one. I'm hoping that it HAS one and that someone in the SO community knows what it is and is willing to help me. Commented Jan 26, 2018 at 10:21
  • @FilipSavic No, if don't understand the problem in your question you cannot say that someone willing to help you. It's not help and support. Commented Jan 27, 2018 at 1:08

1 Answer 1

10

I solved it...

The query needs to look like this:

@Query(
        value = "SELECT * FROM \n" +
                "(institution INNER JOIN user ON institution.user_id = user.id) \n" +
                "LEFT JOIN \n" +
                "(SELECT * FROM \n" +
                "building_institutions \n" +
                "WHERE building_id = :userId)\n" +
                " AS reserved_institutions \n" +
                "ON reserved_institutions.institutions_user_id = kits_nwt.institution.user_id \n" +
                " where reserved_institutions.institutions_user_id IS null \n"
                + "ORDER BY ?#{#pageable}"
        ,
        countQuery = "SELECT count(*) FROM \n" +
                "(institution INNER JOIN user ON institution.user_id = user.id) \n" +
                "LEFT JOIN \n" +
                "(SELECT * FROM \n" +
                "building_institutions \n" +
                "WHERE building_id =:userId)\n" +
                " AS reserved_institutions \n" +
                "ON reserved_institutions.institutions_user_id = kits_nwt.institution.user_id \n" +
                "where reserved_institutions.institutions_user_id IS null \n" +
                "ORDER BY ?#{#pageable}",
        nativeQuery = true)
Page<Institution> findPotentialInstitutionsByBuildingId(@Param("userId") Long userId, Pageable pageable);

I was getting the error at line 4 near WHERE, when my query looked like this:

@Query(
        value = "SELECT username, password, description, location, title, user_id FROM (institution INNER JOIN user ON institution.user_id = user.id) LEFT JOIN\n" +
                "(SELECT * FROM building_institutions WHERE building_institutions.building_id = 1) AS reserved_institutions\n" +
                "ON reserved_institutions.institutions_user_id = kits_nwt.institution.user_id\n" +
                "WHERE reserved_institutions.institutions_user_id IS null ORDER BY ?#{#pageable}",
        nativeQuery = true)
Page<Institution> findPotentialInstitutionsByBuildingId(Long userId, Pageable pageable);

and that was because I didn't add the countQuery parameter to the @Query annotation.

Big thanks to all of you who tried to help.

I hope that I save someone else many hours of misery.

Cheers! :)

Sign up to request clarification or add additional context in comments.

3 Comments

You are welcome :)
I was very struggling with it for long time, but eventually found your self-answer! Thank you very much!
My pleasure! :))

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.