I am trying to implement a simple HQL query of all objects of type A ordered by the following predicate :
a.getListB().get(0).getC().getLastname()
I tried the following HQL query :
select a_ from A a_ order by a_.listB.c.lastname
But I am getting the following exception :
org.hibernate.QueryException: illegal attempt to dereference collection
I have tried the following SQL query but I am getting inconsistent results :
select a.* from A a
left outer join B b on b.a_id=a.id
left outer join C c on b.uploaded_from=c.id
order by c.lastname=(select c_.lastname from A a_
left outer join B b_ on b_.a_id=a_.id
left outer join C c_ on b_.uploaded_from=c_.id
where a.id=a_.id limit 1) asc;
Code snipet :
#Entity
#Table(name = "A")
pubic class A {
private int id;
private List<B> listB;
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "id", unique = true, nullable = false)
public Integer getId() {
return this.id;
}
#OrderBy(clause = "id")
#OneToMany(fetch = FetchType.LAZY, mappedBy = "a")
public List<B> getListB() {
return this.listB;
}
}
#Entity
#Table(name = "B")
pubic class B {
private int id;
private A a;
private C c;
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "id", unique = true, nullable = false)
public Integer getId() {
return this.id;
}
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "a_id", nullable = false)
public A getA() {
return this.a;
}
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "uploaded_from", nullable = false)
public C getC() {
return this.c;
}
}
#Entity
#Table(name = "C")
pubic class C {
private int id;
private String lastname;
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "id", unique = true, nullable = false)
public Integer getId() {
return this.id;
}
#Column(name = "lastname")
public String getLastname() {
return this.lastname;
}
}
Any hints how can I work around this problem please either in HQL, Criteria or even native SQL?
I used the following tables to test one possible solution for your problem further below
create table A (
id UUID
);
create table B (
id UUID,
id_a UUID,
id_c UUID
);
create table C (
id UUID,
lastname varchar(63)
);
insert into A values
('aaaaaaaa-aaaa-aaaa-aaaa-000000000000'),
('aaaaaaaa-aaaa-aaaa-aaaa-000000000001'),
('aaaaaaaa-aaaa-aaaa-aaaa-000000000002'),
('aaaaaaaa-aaaa-aaaa-aaaa-000000000003'),
('aaaaaaaa-aaaa-aaaa-aaaa-000000000004');
insert into C values
('cccccccc-cccc-cccc-cccc-000000000000', 'C zero'),
('cccccccc-cccc-cccc-cccc-000000000001', 'C one'),
('cccccccc-cccc-cccc-cccc-000000000002', 'C two'),
('cccccccc-cccc-cccc-cccc-000000000003', 'C three'),
('cccccccc-cccc-cccc-cccc-000000000004', 'C four'),
('cccccccc-cccc-cccc-cccc-000000000005', 'C five'),
('cccccccc-cccc-cccc-cccc-000000000006', 'C six');
insert into B values
('bbbbbbbb-bbbb-bbbb-bbbb-000000000000', 'aaaaaaaa-aaaa-aaaa-aaaa-000000000000', 'cccccccc-cccc-cccc-cccc-000000000000'),
('bbbbbbbb-bbbb-bbbb-bbbb-000000000001', 'aaaaaaaa-aaaa-aaaa-aaaa-000000000000', 'cccccccc-cccc-cccc-cccc-000000000001'),
('bbbbbbbb-bbbb-bbbb-bbbb-000000000002', 'aaaaaaaa-aaaa-aaaa-aaaa-000000000000', 'cccccccc-cccc-cccc-cccc-000000000002'),
('bbbbbbbb-bbbb-bbbb-bbbb-000000000003', 'aaaaaaaa-aaaa-aaaa-aaaa-000000000001', 'cccccccc-cccc-cccc-cccc-000000000003'),
('bbbbbbbb-bbbb-bbbb-bbbb-000000000004', 'aaaaaaaa-aaaa-aaaa-aaaa-000000000001', 'cccccccc-cccc-cccc-cccc-000000000004'),
('bbbbbbbb-bbbb-bbbb-bbbb-000000000005', 'aaaaaaaa-aaaa-aaaa-aaaa-000000000001', 'cccccccc-cccc-cccc-cccc-000000000005'),
('bbbbbbbb-bbbb-bbbb-bbbb-000000000006', 'aaaaaaaa-aaaa-aaaa-aaaa-000000000002', 'cccccccc-cccc-cccc-cccc-000000000006'),
('bbbbbbbb-bbbb-bbbb-bbbb-000000000007', 'aaaaaaaa-aaaa-aaaa-aaaa-000000000002', 'cccccccc-cccc-cccc-cccc-000000000000'),
('bbbbbbbb-bbbb-bbbb-bbbb-000000000008', 'aaaaaaaa-aaaa-aaaa-aaaa-000000000002', 'cccccccc-cccc-cccc-cccc-000000000001'),
('bbbbbbbb-bbbb-bbbb-bbbb-000000000009', 'aaaaaaaa-aaaa-aaaa-aaaa-000000000003', 'cccccccc-cccc-cccc-cccc-000000000002'),
('bbbbbbbb-bbbb-bbbb-bbbb-000000000010', 'aaaaaaaa-aaaa-aaaa-aaaa-000000000003', 'cccccccc-cccc-cccc-cccc-000000000003'),
('bbbbbbbb-bbbb-bbbb-bbbb-000000000011', 'aaaaaaaa-aaaa-aaaa-aaaa-000000000003', 'cccccccc-cccc-cccc-cccc-000000000004'),
('bbbbbbbb-bbbb-bbbb-bbbb-000000000012', 'aaaaaaaa-aaaa-aaaa-aaaa-000000000004', 'cccccccc-cccc-cccc-cccc-000000000005'),
('bbbbbbbb-bbbb-bbbb-bbbb-000000000013', 'aaaaaaaa-aaaa-aaaa-aaaa-000000000004', 'cccccccc-cccc-cccc-cccc-000000000006'),
('bbbbbbbb-bbbb-bbbb-bbbb-000000000014', 'aaaaaaaa-aaaa-aaaa-aaaa-000000000004', 'cccccccc-cccc-cccc-cccc-000000000000'),
('bbbbbbbb-bbbb-bbbb-bbbb-000000000015', 'aaaaaaaa-aaaa-aaaa-aaaa-000000000000', 'cccccccc-cccc-cccc-cccc-000000000001'),
('bbbbbbbb-bbbb-bbbb-bbbb-000000000016', 'aaaaaaaa-aaaa-aaaa-aaaa-000000000001', 'cccccccc-cccc-cccc-cccc-000000000002'),
('bbbbbbbb-bbbb-bbbb-bbbb-000000000017', 'aaaaaaaa-aaaa-aaaa-aaaa-000000000002', 'cccccccc-cccc-cccc-cccc-000000000003');
Unique id_a entries are numbered via this intermediate select:
select id,id_a,id_c,ROW_NUMBER()
over (partition by id_a order by id_a) as rowNumber
from B as aggregate;
Result:
id | id_a | id_c | rownumber
--------------------------------------+--------------------------------------+--------------------------------------+-----------
bbbbbbbb-bbbb-bbbb-bbbb-000000000000 | aaaaaaaa-aaaa-aaaa-aaaa-000000000000 | cccccccc-cccc-cccc-cccc-000000000000 | 1
bbbbbbbb-bbbb-bbbb-bbbb-000000000015 | aaaaaaaa-aaaa-aaaa-aaaa-000000000000 | cccccccc-cccc-cccc-cccc-000000000001 | 2
bbbbbbbb-bbbb-bbbb-bbbb-000000000001 | aaaaaaaa-aaaa-aaaa-aaaa-000000000000 | cccccccc-cccc-cccc-cccc-000000000001 | 3
bbbbbbbb-bbbb-bbbb-bbbb-000000000002 | aaaaaaaa-aaaa-aaaa-aaaa-000000000000 | cccccccc-cccc-cccc-cccc-000000000002 | 4
bbbbbbbb-bbbb-bbbb-bbbb-000000000004 | aaaaaaaa-aaaa-aaaa-aaaa-000000000001 | cccccccc-cccc-cccc-cccc-000000000004 | 1
bbbbbbbb-bbbb-bbbb-bbbb-000000000016 | aaaaaaaa-aaaa-aaaa-aaaa-000000000001 | cccccccc-cccc-cccc-cccc-000000000002 | 2
bbbbbbbb-bbbb-bbbb-bbbb-000000000003 | aaaaaaaa-aaaa-aaaa-aaaa-000000000001 | cccccccc-cccc-cccc-cccc-000000000003 | 3
bbbbbbbb-bbbb-bbbb-bbbb-000000000005 | aaaaaaaa-aaaa-aaaa-aaaa-000000000001 | cccccccc-cccc-cccc-cccc-000000000005 | 4
bbbbbbbb-bbbb-bbbb-bbbb-000000000017 | aaaaaaaa-aaaa-aaaa-aaaa-000000000002 | cccccccc-cccc-cccc-cccc-000000000003 | 1
bbbbbbbb-bbbb-bbbb-bbbb-000000000006 | aaaaaaaa-aaaa-aaaa-aaaa-000000000002 | cccccccc-cccc-cccc-cccc-000000000006 | 2
bbbbbbbb-bbbb-bbbb-bbbb-000000000007 | aaaaaaaa-aaaa-aaaa-aaaa-000000000002 | cccccccc-cccc-cccc-cccc-000000000000 | 3
bbbbbbbb-bbbb-bbbb-bbbb-000000000008 | aaaaaaaa-aaaa-aaaa-aaaa-000000000002 | cccccccc-cccc-cccc-cccc-000000000001 | 4
bbbbbbbb-bbbb-bbbb-bbbb-000000000011 | aaaaaaaa-aaaa-aaaa-aaaa-000000000003 | cccccccc-cccc-cccc-cccc-000000000004 | 1
bbbbbbbb-bbbb-bbbb-bbbb-000000000010 | aaaaaaaa-aaaa-aaaa-aaaa-000000000003 | cccccccc-cccc-cccc-cccc-000000000003 | 2
bbbbbbbb-bbbb-bbbb-bbbb-000000000009 | aaaaaaaa-aaaa-aaaa-aaaa-000000000003 | cccccccc-cccc-cccc-cccc-000000000002 | 3
bbbbbbbb-bbbb-bbbb-bbbb-000000000012 | aaaaaaaa-aaaa-aaaa-aaaa-000000000004 | cccccccc-cccc-cccc-cccc-000000000005 | 1
bbbbbbbb-bbbb-bbbb-bbbb-000000000013 | aaaaaaaa-aaaa-aaaa-aaaa-000000000004 | cccccccc-cccc-cccc-cccc-000000000006 | 2
bbbbbbbb-bbbb-bbbb-bbbb-000000000014 | aaaaaaaa-aaaa-aaaa-aaaa-000000000004 | cccccccc-cccc-cccc-cccc-000000000000 | 3
(18 rows)
We can now obtain only the first C entry associated to a A entry by selecting only entries with rowNumber=1:
select *
from (
select id,id_a,id_c,ROW_NUMBER()
over (partition by id_a order by id_a) as rowNumber from B)
as aggregate
where aggregate.rowNumber=1;
Result:
id | id_a | id_c | rownumber
--------------------------------------+--------------------------------------+--------------------------------------+-----------
bbbbbbbb-bbbb-bbbb-bbbb-000000000000 | aaaaaaaa-aaaa-aaaa-aaaa-000000000000 | cccccccc-cccc-cccc-cccc-000000000000 | 1
bbbbbbbb-bbbb-bbbb-bbbb-000000000004 | aaaaaaaa-aaaa-aaaa-aaaa-000000000001 | cccccccc-cccc-cccc-cccc-000000000004 | 1
bbbbbbbb-bbbb-bbbb-bbbb-000000000017 | aaaaaaaa-aaaa-aaaa-aaaa-000000000002 | cccccccc-cccc-cccc-cccc-000000000003 | 1
bbbbbbbb-bbbb-bbbb-bbbb-000000000011 | aaaaaaaa-aaaa-aaaa-aaaa-000000000003 | cccccccc-cccc-cccc-cccc-000000000004 | 1
bbbbbbbb-bbbb-bbbb-bbbb-000000000012 | aaaaaaaa-aaaa-aaaa-aaaa-000000000004 | cccccccc-cccc-cccc-cccc-000000000005 | 1
(5 rows)
By joining C it is now possible to sort by lastname:
select aggregate.id_a,c.lastname
from (
select id,id_a,id_c,ROW_NUMBER()
over (partition by id_a order by id_a) as rowNumber from B)
as aggregate
join C as c on aggregate.id_c=c.id where aggregate.rowNumber=1
order by c.lastname;
Result:
id_a | lastname
--------------------------------------+----------
aaaaaaaa-aaaa-aaaa-aaaa-000000000004 | C five
aaaaaaaa-aaaa-aaaa-aaaa-000000000003 | C four
aaaaaaaa-aaaa-aaaa-aaaa-000000000001 | C four
aaaaaaaa-aaaa-aaaa-aaaa-000000000002 | C three
aaaaaaaa-aaaa-aaaa-aaaa-000000000000 | C zero
(5 rows)
(Tested with Postgres 14.3)
I have 3 tables and a ManyToMany relationship between usuario and projeto, and I'm having a headche to make it search accordly :
usuario
+-------------+-------------+
| idMatricula | nomeUsuario |
+-------------+-------------+
| 1 | Victor |
| 12345 | Juquinha |
| 2 | Nilton |
| 3 | Fatima |
| 4 | Bianca |
| 4422 | Pedrinho |
+-------------+-------------+
projeto
+-----------+----------------+--------------+
| idprojeto | nomeProjeto | faseProjeto |
+-----------+----------------+--------------+
| 1 | APS_6_semestre | Em Andamento |
| 2 | APS_7_semestre | Em testes |
| 3 | APS_8_semestre | Em testes |
| 4 | TCC | Concluido |
+-----------+----------------+--------------+
projeto_has_usuario
+-------------------+---------------------+
| projeto_idprojeto | usuario_idMatricula |
+-------------------+---------------------+
| 1 | 1 |
| 1 | 2 |
| 1 | 3 |
| 2 | 2 |
+-------------------+---------------------+
I'm trying to query only the projects associated to the user, but my query doesnt work and I dont know if it is a semantic error or an annotation error. Here is my mapped class:
Projeto:
#Entity
#Table(name="projeto")
public class Projeto {
#GeneratedValue
#Id
#Column(name="idprojeto", nullable = false)
private int idprojeto;
#Column(name="nomeProjeto", nullable = false)
private String nomeProjeto;
#Column(name="faseProjeto", nullable = false)
private String faseProjeto;
#ManyToMany(mappedBy="projetos")
private List<Usuario> usuarios;
Usuario:
#Entity
#Table(name="usuario")
public class Usuario {
#Id
#Column(name="idMatricula", nullable = false)
private String id;
#Column(name="nomeUsuario", nullable = false)
private String nomeUsuario;
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(name="projeto_has_usuario",
joinColumns={#JoinColumn(name="usuario_idMatricula")},
inverseJoinColumns={#JoinColumn(name="projeto_idprojeto")})
private List<Projeto> projetos;
Here is my query:
TypedQuery<Usuario> listaUsuario = manager.createQuery("SELECT u FROM Usuario as u", Usuario.class);
// Some validation ..
TypedQuery<Projeto> listaTabela = manager.createQuery("SELECT p FROM projeto p "
+ "JOIN p.usuarios u WHERE p.idprojeto MEMBER OF u.projetos", Projeto.class);
for (Projeto projetos : listaTabela.getResultList()) {
System.out.println("Nome: " + projetos.getNomeProjeto() + "\nID: " + projetos.getIdprojeto()
+ "\nFase: " + projetos.getFaseProjeto());
Returns me:
Nome: APS_6_semestre
ID: 1
Fase: Em Andamento
I'm using Eclipse IDE 4.7.2, Hibernate 5.2.12 and JPA 2.1.
The environment is Java, Spring-boot, Hibernat, QueryDSL, MySQL.
I have table structure
Episode
+----+-------------+--------
| id | address_id | eventno
+----+-------------+--------
| 5 | 27 | F123
| 6 | 30 | F456
| 7 | 45 | F789
+----+-------------+--------
#Entity
public class Episode {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#NotEmpty
private String eventno;
#ManyToOne(cascade = CascadeType.ALL)
private Address address;
Episode_Person
+----+--------------+--------------+------------+-----------+
| id | episode_role | primary_flag | episode_id | person_id |
+----+--------------+--------------+------------+-----------+
| 19 | Buyer | | 5 | 1 |
| 20 | Subject | | 5 | 2 |
| 23 | Witness | | 6 | 3 |
| 24 | Child | | 6 | 4 |
| 27 | Buyer | | 5 | 3 |
| 63 | Investor | | 5 | 4 |
| 64 | Subject | | 7 | 1 |
| 65 | Subject | | 7 | 3 |
#Entity
public class EpisodePerson {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne
#Valid
private Person person;
#ManyToOne
private Episode episode;
Person
+----+-----------+----------+
| id | firstname | surname |
+----+-----------+----------+
| 1 | Clint | eastwood |
| 2 | Angelina | joilee |
| 3 | Brad | pitt |
| 4 | Jennifer | aniston |
#Entity
#Table(uniqueConstraints = #UniqueConstraint(columnNames = {"nia"}))
public class Person {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String surname;
private String firstname;
private String gender;
So each episode has multiple people. And the join table is Episode_Person.
My UI has a datatable with a filter on each column:
The filtering already works on Event and Address. And looks like this predicate in QueryDSL:
BooleanBuilder where = new BooleanBuilder();
if (pagination.getFilterBy().getMapOfFilters().get("eventno")!=null) {
where.and(qEpisode.eventno.containsIgnoreCase(pagination.getFilterBy().getMapOfFilters().get("eventno")));
}
if (pagination.getFilterBy().getMapOfFilters().get("address")!=null) {
where.and(qEpisode.address.formattedAddress.containsIgnoreCase(pagination.getFilterBy().getMapOfFilters().get("address")));
}
where.and(qEpisode.creatingUser.eq(user));
List<Episode> e = episodeRepository.findAll(where);
How would I now add a 3rd predicate for case name where case name is constructed of the first two people returned in the collection of people against a episode?
UPDATE
For clarification the DTO thats backs the UI view contains the "casename" attribute. It is created in the service layer when Domain objects are converted to DTO:
episodeDashboard.setNames(episodePersonList.get(0).getPerson().getSurname().toUpperCase() +" & " +episodePersonList.get(1).getPerson().getSurname().toUpperCase());
Not easily unless you delegate some of the processing to the database.
If we can get the case_name property to be populated at the database tier rather than as a derived property in the application logic then the front-end code becomes trivial.
We can do this by means of a view. The exact definition of this will depend on your database however the output would be something like this:
episode_summary_vw
+------------+-------------------------+
| epsiode_id | case_name |
+------------+-------------------------+
| 5 | Eastwood & Joilee|
| 6 | Pitt & Aniston|
| 7 | Aniston & Pitt|
+------------+-------------------------+
For Oracle it looks like LISTAGG function is what you would want and for MySQL the GROUP_CONCAT functions. In MySQL then I think this would look something like:
CREATE VIEW episode_summary_vw as
SELECT ep.episode_id, GROUP_CONCAT(p.surname SEPARATOR ' & ')
FROM episode_person ep
INNER JOIN person p on p.id = ep.person_id
GROUP BY ep.episode_id;
-- todo: needs limit to first 2 records
Once we have a view then we can simply map the case_name to the Episode entity using the #SecondaryTable functionality of JPA:
#Entity
#Table(name = "episodes")
#SecondaryTable(name = "episode_summary_vw", primaryKeyJoinColumna = #PrimaryKeyJoinColumn(name="episode_id", reference_column_name="id"))
public class Episode {
#Column(name ="case_name", table = "episode_summary_vw")
private String caseName;
}
You then filter and sort on the property as for any other field:
if (pagination.getFilterBy().getMapOfFilters().get("caseName")!=null) {
where.and(qEpisode.caseName.containsIgnoreCase(pagination.getFilterBy().
getMapOfFilters().get("caseName")));
}
I have three related tables like below:
+-------------+---------+------------+
| customer_id | name | surname |
+-------------+---------+------------+
| 1 | Jan | Bielecki |
| 2 | Adam | Bielen |
.....
+----------+--------+---------------------+-------------+
| order_id | amount | date | customer_id |
+----------+--------+---------------------+-------------+
| 1 | 10.23 | 2017-02-15 00:00:00 | 1 |
| 2 | 20.56 | 2017-02-16 00:00:00 | 1 |
| 3 | 30.57 | 2017-02-17 00:00:00 | 2 |
| 4 | 40.52 | 2017-02-18 00:00:00 | 2 |
| 5 | 50.30 | 2017-02-19 00:00:00 | 1 |
.....
+-----------------+-----------+------------+----------+
| order_detail_id | item_name | item_price | order_id |
+-----------------+-----------+------------+----------+
| 1 | item 1 | 2.00 | 1 |
| 2 | item 2 | 2.50 | 1 |
| 3 | item 3 | 3.00 | 1 |
| 4 | item 4 | 4.00 | 2 |
| 5 | item 5 | 5.50 | 2 |
| 6 | item 6 | 7.60 | 3 |
| 7 | item 7 | 5.00 | 3 |
| 8 | item 8 | 3.00 | 4 |
| 9 | item 9 | 7.00 | 4 |
| 10 | item 10 | 8.00 | 4 |
| 11 | item 11 | 2.00 | 5 |
| 12 | item 12 | 2.50 | 5 |
.....
Firstly i'm fighting with connect first and second table. For connect surnames with sum of amount.
I'm trying like this:
select sum(o.amount) as totalSum
from Order as o,
Customer as c
join c.surname as surname
where c.orders:=o.customer
group by o.customer
order by sum(o.amount) desc
with changing to many ways this section: where c.orders:=o.customer
The most common error is NullPointerException.
Before done this in SQL:
Table customer_id <-> total_amount
SELECT customer_id,
SUM(amount) as total_amount,
COUNT(amount) as orders_quantity
FROM softhis_db.orders
GROUP BY customer_id;
Table customer_id <-> 3 most exp. orders + dates
SELECT orders.customer_id, orders.amount, orders.date
FROM orders_details
RIGHT JOIN orders
ON orders.order_id = orders_details.order_id
ORDER BY amount DESC
LIMIT 3;
Customer:
#Entity
#Table(name = "customers")
public class Customer {
#Id
#Column(name = "customer_id")
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "name", length = 50)
private String name;
#Column(name = "surname", length = 50)
private String surname;
#OneToMany(mappedBy = "customer")
private Set<Order> orders = new HashSet<>();
Order:
#Entity
#Table(name = "orders")
public class Order {
#Id
#Column(name = "order_id")
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "date")
private Date date;
#Digits(integer = 5, fraction = 2)
#Column(name = "amount")
private BigDecimal amount;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "customer_id")
private Customer customer;
#OneToMany(mappedBy = "order")
private Set<OrderDetail> ordersDetails = new HashSet<>();
OrderDetail:
#Entity
#Table(name = "orders_details")
public class OrderDetail {
#Id
#Column(name = "order_detail_id")
#GeneratedValue(strategy = GenerationType.AUTO)
private Lon id;
#Column(name = "item_name", length = 50)
private String itemName;
#Digits(integer = 5, fraction = 2)
#Column(name = "item_price")
private BigDecimal itemPrice;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "order_id")
private Order order;
The point is how to do this properly in HQL ? Next step will be searching by surname and getting result like 'my target'.
My target is:
+---------+---------------+
| surname | sum of amount |
+---------+---------------+
|Bielecki | 150.40 |
|Bielen | 130.34 |
......
+-----------------------------------+--------------------+
| surname | 3 most expensive orders | date |
+-----------------------------------+--------------------+
|Bielecki | 120.23 |2017-02-15 00:00:00 |
|Bielecki | 80.20 |2017-02-18 00:00:00 |
|Bielecki | 20.20 |2017-02-19 00:00:00 |
+---------+-------------------------+--------------------+
|Bielen | 190.23 |2017-02-15 00:00:00 |
|Bielen | 80.20 |2017-02-18 00:00:00 |
|Bielen | 20.20 |2017-02-19 00:00:00 |
+---------+-------------------------+--------------------+
.....
Try these queries
SELECT
customers.surname
, SUM(amount) "sum of amount"
FROM
customers
INNER JOIN
orders
ON
customers.customer_id = orders.customer_id
GROUP BY
customers.surname
ORDER BY
customers.surname ASC
For the 3 most expensive orders per surname you need to use user variables to create ranking.
And filter on that ranking.
SELECT
customers.surname
, orders_ranked.amount AS "3 most expensive orders"
, orders_ranked.date
FROM (
SELECT
*
, (
CASE
WHEN
#customer_id = orders.customer_id
THEN
#rank := #rank + 1
ELSE
#rank := 1
END
)
AS
rank
, #customer_id := orders.customer_id
FROM
orders
CROSS JOIN (
SELECT
#customer_id := 0
, #rank := 0
)
AS
init_user_variables
ORDER BY
orders.customer_id ASC
, orders.amount DESC
)
AS
orders_ranked
INNER JOIN
customers
ON
orders_ranked.customer_id = customers.customer_id
WHERE
orders_ranked.rank <= 3
I figured out how to translate those SQL queries to HQL.
In order:
1.
select o.customer.surname, sum(o.amount) as s from Order as o group by o.customer
2.
select o.customer.surname, o.amount, o.date from Order as o, OrderDetail as od
The GenericVehicle represent a vehicle which may have 0 or more GenericVehicleAccessory.
#Entity
#Inheritance(strategy = InheritanceType.JOINED)
public class GenericVehicle extends GenericEntity {
#Id
private Long id;
#Column(nullable=false)
#NotNull(message="{GenericVehicle.vehicleName.notNull")
#Size(max=128, message="{GenericVehicle.vehicleName.size")
private String vehicleName;
#OneToMany(mappedBy = "genericVehicle", cascade = { CascadeType.ALL }, orphanRemoval = true, fetch = FetchType.LAZY)
private Set<GenericVehicleAccessory> accessories;
// ..
}
#Entity
#Table(name = "GENERICVEHICLEACCESSORIES")
public class GenericVehicleAccessory extends GenericEntity {
#Id
private long id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "GENERICVEHICLE_ID")
private GenericVehicle genericVehicle;
private String name;
// ..
}
I would like to perform a query which selects all GenericVehicle(s) which owns a Set (accessories) of a given criteria set.
For example:
+----+-------------------+
| ID | VEHICLENAME |
+----+-------------------+
| 1 | Toyota Auris |
| 2 | Volkswagen Passat |
| 3 | Bentley Arnage |
| 4 | Hyundai Accent |
| 5 | Toyota Auris |
+----+-------------------+
+-------------------+----------------------------------+
| GENERICVEHICLE_ID | NAME |
+-------------------+----------------------------------+
| 1 | Leather seats |
| 1 | Electronic stability control |
| 2 | Power steering |
| 4 | ABS |
| 4 | Airbag |
| 4 | Cruise control |
| 5 | Leather seats |
| 5 | Electronic stability control |
+-------------------+----------------------------------+
A criteria like this:
criteria.setVehicleName="Toyota Auris";
new GenericVehicleAccessory tmp0 = new GenericVehicleAccessory();
tmp0.setName="Leather Seats";
new GenericVehicleAccessory tmp1 = new GenericVehicleAccessory();
tmp1.setName="Electronic stability control";
criteria.addToAccessory(tmp0);
criteria.addToAccessory(tmp1);
would select the GenericVehicle entity with ID=1 (since ID=5 not have Electronic Stability Control).
How can I do that by using JPA Criteria API?