No nie samym HQLem człowiek żyje.
Po pierwsze jest takie coś jak EntityManager i jeżeli poprosisz go o to by np. znalazł kota o podanym identyfikatorze to wystarczy napisać:
em.find(Cat.class, catId);
On zamieni to na odpowiednie zapytanie SQL, a wynik zmapuje na obiekt klasy Cat.
Po drugie można użyć HQL czyli języka podobnego do SQLa:
em.createQuery("Select cat from Cat where cat.catId=?").setParameter(1, catId).getSingleResult();
Po trzecie można użyć Criteria API, czyli zestawu interfejsów i klas, które pozwalają na budowanie zapytań HQL, ale jednocześnie zabezpieczają przed literówkami, a to dzięki kontroli typów:
CriteriaQuery<Cat> criteria = builder.createQuery( Cat.class );
Root<Cat> cat = criteria.from( Cat.class );
criteria.select( cat );
criteria.where( builder.lt( cat.get( Cat_.catId ), catId ) );
Cat garfield = em.createQuery( criteria ).getSingleResult();
Po czwarte można użyć jeszcze native query, czyli za pomocą EM wywołać zwykłe zapytania SQL. Tylko po co ;)
Moje pytanie - co rozumiesz przez "zaawansowane zapytanie"?