SQL Jpa,从group by中选择最后一行

时间:2012-11-08 13:03:39

标签: java jpa jpql

我需要返回表格位置中每个设备的最后一行

我的表名是:位置

+------------+----------+--------------+--------------+----------+  
| locationId | deviceId | dataRegistro | horaRegistro | location |  
+------------+----------+--------------+--------------+----------+  
|         50 |        1 |   2012-11-07 |     15:35:00 |      A12 |  
+------------+----------+--------------+--------------+----------+  
|         51 |        1 |   2012-11-07 |     15:37:40 |       B2 |  
+------------+----------+--------------+--------------+----------+  
|         52 |        2 |   2012-11-07 |     15:35:12 |       B8 |  
+------------+----------+--------------+--------------+----------+  
|         53 |        2 |   2012-11-07 |     15:35:40 |      50C |  
+------------+----------+--------------+--------------+----------+  
|         54 |        2 |   2012-11-07 |     15:40:00 |      94A |  
+------------+----------+--------------+--------------+----------+  

从我选择的一个设备的最后一行中选择

select L from Location L where deviceId = :deviceId order by "dataRegistro" DESC, "horaRegistro" DESC limit 1

现在如何选择每个设备的所有最新位置? :(我使用Java JPA。

感谢,

伊万德罗

7 个答案:

答案 0 :(得分:5)

如果ID是有序的,那么以后记录的记录对应于以后的日期,你可以使用这个查询(我不打算将字符串转换为日期,这会使它慢于可接受的。):

select L from Location L where deviceId = :deviceId order by L.locationId DESC 

并限制在Java代码中返回的行数:

//EntityManager em; defined earlier
Query q = em.createQuery("select L from Location L where deviceId = :deviceId order by L.locationId DESC ");
q.setParameter("deviceId", "theDeviceIdIWantToQuery");
q.setMaxResults(1);
List<Location> results=query.getResultList();

如果给定的deviceId没有行,或者包含1个Location项的List - 最后一行,这将是一个空列表。

如果要一次性为所有设备选择最新位置,可以使用IN子句和子查询:

select L2 FROM Location L2 WHERE L2.locationId IN
    (select L.locationId from Location L 
    where L.deviceId = :deviceId 
    order by L.locationId DESC 
    group by L.deviceId)

可悲的是,JPQL doesn't permit using subqueries in the FROM clause,所以尽管我选择这样做,但只能使用原生查询功能,这样使用起来会更加不方便。

顺便说一下,在我看来,像你一样存储时间戳是一种不好的做法。它没有适当的可索引性,在查询和订购时会给您带来麻烦,只是一场普通的噩梦。我会认真重新考虑你的架构的这一部分。

答案 1 :(得分:1)

是的我使用JPA,这个例子只是为了展示我需要的东西

我的JPA 查询选择一个设备是

Query q = em.createQuery("select TL from TRKLocation TL where   
TL.device.deviceId = :deviceId and TL.msgError = '' order by 
TL.dataRegistro DESC, TL.horaRegistro DESC");
        q.setParameter("deviceId", deviceId);           
        q.setMaxResults(1);

list = q.getResultList();

现在,我需要查询从所有设备中选择最后一个位置:)

答案 2 :(得分:0)

试试这个

select top (1) location from location where deviceid=:deviceid 
 order by dateregistro,horaregistro desc

答案 3 :(得分:0)

这样的事情怎么样:

SELECT locationId
  FROM location
 WHERE dateregistro + horaregistro = (SELECT MAX(datergistro + horaregistro)
                                        FROM location
                                       WHERE deviceid = :deviceid)
   AND deviceid = :deviceid

我不确定日期计算的正确性,但也许您可以创建一个新列,其中合并日期和时间。

答案 4 :(得分:0)

我不明白为什么你不存储简单的时间戳而不是有两列日期和时间。这使得运行所需的选择变得更加困难。这是一个示例,如果时间戳可用,它应该如何工作(从查看JPQL Spec部分4.6.16这应该工作)

Select loc From Location loc where loc.ts_registered = 
(Select MAX(subloc.ts_registered) From Location subloc where subloc.deviceId = loc.deviceId)

我没有测试它,但我认为这应该有效。但请注意,此查询在中型到大型数据集上的运行速度会非常慢。您绝对应该向列deviceId添加索引。

此外,我建议您重新考虑您的数据模型,因为此查询需要构建笛卡尔积(随着数据的增长,速度会相当快)

答案 5 :(得分:0)

如果dateregistro和horaregistro是字符串,您可以尝试此查询:

select * from location l1
where dateregistro + horaregistro = (select max(dateregistro + horaregistro) from
location l2 where l2.deviceid = l1.deviceid)

更好的是,如果locationid字段是唯一的排序键,则可以在其上应用where条件:

select * from location l1
where locationid = (select max(locationid) from
location l2 where l2.deviceid = l1.deviceid)

答案 6 :(得分:0)

Query q= em.createQuery("Select D from DeviceInfo D WHERE D.devLastPing IN (SELECT MAX(DD.devLastPing) FROM DeviceInfo DD WHERE DD.devLastPing >= :startDate AND DD.devLastPing <= :endDate)");

        q.setParameter("startDate", startDate)
                .setParameter("endDate", endDate);
        List<DeviceInfo> list = (List<DeviceInfo>)q.getResultList();

你可以使用类似的东西。对不起,在我的情况下,我将它用于设备目的。对不起,我知道为时已晚,但它可以帮助某人,如果有人先前回复,我会再次感到抱歉。谢谢