如何实现这个多重 select 以及使用 Hibernate 条件的查询?
How to implement this multiple select and where query with Hibernate criteria?
我遇到了 Hibernate 条件查询问题。
Table DataStatus
数据如下所示:
|-------------|--------------|--------------|---------------------|
| name | info | server | starttime |
|-------------|--------------|--------------|---------------------|
| Bob | information1 | www1 | 2018-02-14 10:32:43 |
| Alice | information2 | www3 | 2018-02-14 17:34:43 |
| Bob | information3 | www2 | 2018-02-14 10:32:43 |
| Alice | information4 | www1 | 2018-02-14 11:25:51 |
| Alice | information5 | www2 | 2018-02-14 08:42:25 |
| Bob | information6 | www3 | 2018-02-14 10:32:43 |
|-------------|--------------|--------------|---------------------|
查询如下所示:
SELECT * FROM DataStatus sts
WHERE sts.server IS NOT NULL
AND sts.name = 'Bob'
AND sts.starttime < (
SELECT starttime FROM DataStatus
WHERE name = 'Alice' AND server = sts.server);
结果如下所示:
|-------------|--------------|--------------|---------------------|
| name | info | server | starttime |
|-------------|--------------|--------------|---------------------|
| Bob | information1 | www1 | 2018-02-14 10:32:43 |
| Bob | information6 | www3 | 2018-02-14 10:32:43 |
|-------------|--------------|--------------|---------------------|
我试过如下的方法:
Criteria criteria = session.CreateCriteria(DataStatus.class);
criteria.add(
Restrictions.and(
criteria.add(Restrictions.isNotNull("server")),
criteria.add(Restrictions.eq("name", "Bob")),
criteria.add(Restrictions.lt("starttime", ))
)
);
我不知道如何使用 Hibernate 标准实现这个嵌套的 where 和 select 查询?
提前致谢。
我不熟悉 Hibernate,但你可以重写查询以避免子查询
SELECT bob.* /** Only include cols from Bob records */
FROM DataStatus bob
/** Only include rows with a later Alice record on the same server */
JOIN DataStatus alice
ON alice.name = 'Alice'
AND alice.server = bob.server
AND alice.starttime > bob.starttime
WHERE bob.name = 'Bob'
您可能会发现这与 Hibernate 语法配合得更好
N.B. 这假定每个名称和服务器最多有一个记录。这可以通过 (name,server)
上的 UNIQUE KEY 强制执行
此假设是基于您原始查询中的条件 WHERE {bob server row starttime} < SELECT {alice server row starttime}
,如果 SELECT 可以 return 多行
我的建议是继续尝试,多看 Javadoc,在 IDE 中试验。如果你放弃了,试试下面的方法(假设你的 table 是在 class DataStatus
中建模的):
CriteriaBuilder criteriaBuilder = session.getCriteriaBuilder();
CriteriaQuery<DataStatus> criteriaQuery = criteriaBuilder.createQuery(DataStatus.class);
Root<DataStatus> root = criteriaQuery.from(DataStatus.class);
Subquery<Date> subquery = criteriaQuery.subquery(Date.class);
Root<DataStatus> innerRoot = subquery.from(DataStatus.class);
subquery.select(innerRoot.get("startTime"))
.where(criteriaBuilder.and(criteriaBuilder.equal(innerRoot.get("name"), "Alice"),
criteriaBuilder.equal(innerRoot.get("server"), root.get("server"))));
criteriaQuery.select(root).where(
criteriaBuilder.and( criteriaBuilder.isNotNull( root.get( "server" ) ),
criteriaBuilder.equal(root.get("name"), "Bob" ),
criteriaBuilder.lessThan(root.<Date> get("startTime"), subquery)
) );
Query<DataStatus> query = session.createQuery(criteriaQuery);
List<DataStatus> resultList = query.getResultList();
我遇到了 Hibernate 条件查询问题。
Table DataStatus
数据如下所示:
|-------------|--------------|--------------|---------------------|
| name | info | server | starttime |
|-------------|--------------|--------------|---------------------|
| Bob | information1 | www1 | 2018-02-14 10:32:43 |
| Alice | information2 | www3 | 2018-02-14 17:34:43 |
| Bob | information3 | www2 | 2018-02-14 10:32:43 |
| Alice | information4 | www1 | 2018-02-14 11:25:51 |
| Alice | information5 | www2 | 2018-02-14 08:42:25 |
| Bob | information6 | www3 | 2018-02-14 10:32:43 |
|-------------|--------------|--------------|---------------------|
查询如下所示:
SELECT * FROM DataStatus sts
WHERE sts.server IS NOT NULL
AND sts.name = 'Bob'
AND sts.starttime < (
SELECT starttime FROM DataStatus
WHERE name = 'Alice' AND server = sts.server);
结果如下所示:
|-------------|--------------|--------------|---------------------|
| name | info | server | starttime |
|-------------|--------------|--------------|---------------------|
| Bob | information1 | www1 | 2018-02-14 10:32:43 |
| Bob | information6 | www3 | 2018-02-14 10:32:43 |
|-------------|--------------|--------------|---------------------|
我试过如下的方法:
Criteria criteria = session.CreateCriteria(DataStatus.class);
criteria.add(
Restrictions.and(
criteria.add(Restrictions.isNotNull("server")),
criteria.add(Restrictions.eq("name", "Bob")),
criteria.add(Restrictions.lt("starttime", ))
)
);
我不知道如何使用 Hibernate 标准实现这个嵌套的 where 和 select 查询?
提前致谢。
我不熟悉 Hibernate,但你可以重写查询以避免子查询
SELECT bob.* /** Only include cols from Bob records */
FROM DataStatus bob
/** Only include rows with a later Alice record on the same server */
JOIN DataStatus alice
ON alice.name = 'Alice'
AND alice.server = bob.server
AND alice.starttime > bob.starttime
WHERE bob.name = 'Bob'
您可能会发现这与 Hibernate 语法配合得更好
N.B. 这假定每个名称和服务器最多有一个记录。这可以通过 (name,server)
上的 UNIQUE KEY 强制执行此假设是基于您原始查询中的条件 WHERE {bob server row starttime} < SELECT {alice server row starttime}
,如果 SELECT 可以 return 多行
我的建议是继续尝试,多看 Javadoc,在 IDE 中试验。如果你放弃了,试试下面的方法(假设你的 table 是在 class DataStatus
中建模的):
CriteriaBuilder criteriaBuilder = session.getCriteriaBuilder();
CriteriaQuery<DataStatus> criteriaQuery = criteriaBuilder.createQuery(DataStatus.class);
Root<DataStatus> root = criteriaQuery.from(DataStatus.class);
Subquery<Date> subquery = criteriaQuery.subquery(Date.class);
Root<DataStatus> innerRoot = subquery.from(DataStatus.class);
subquery.select(innerRoot.get("startTime"))
.where(criteriaBuilder.and(criteriaBuilder.equal(innerRoot.get("name"), "Alice"),
criteriaBuilder.equal(innerRoot.get("server"), root.get("server"))));
criteriaQuery.select(root).where(
criteriaBuilder.and( criteriaBuilder.isNotNull( root.get( "server" ) ),
criteriaBuilder.equal(root.get("name"), "Bob" ),
criteriaBuilder.lessThan(root.<Date> get("startTime"), subquery)
) );
Query<DataStatus> query = session.createQuery(criteriaQuery);
List<DataStatus> resultList = query.getResultList();