【问题标题】:SQL Jpa, Select last row from group bySQL Jpa,从分组中选择最后一行
【发布时间】:2012-11-08 13:03:39
【问题描述】:

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

我的表名是:位置

+------------+----------+--------------+--------------+----------+  
| 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。

谢谢,

埃文德罗

【问题讨论】:

    标签: java jpa jpql


    【解决方案1】:

    如果 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 个位置项的列表 - 最后一个。

    如果您想一次性选择所有设备的最新位置,可以使用 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,虽然我会选择这样做,但只能通过使用本机查询功能才能实现,这使用起来更不方便。

    顺便说一下,在我看来,像你这样存储时间戳是一种不好的做法。它不能正确索引,在查询和排序时会遇到麻烦,简直就是一场噩梦。我会认真重新考虑您架构的这一部分。

    【讨论】:

      【解决方案2】:

      是的,我使用 JPA,这个例子只是为了演示我需要什么

      My 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();
      

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

      【讨论】:

        【解决方案3】:

        这样的事情怎么样:

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

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

        【讨论】:

          【解决方案4】:

          试试这个

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

          【讨论】:

          • 您好,感谢回复,但我想选择所有设备的最后一个位置
          • @user690093 这将为您提供您提供设备 ID 的设备的最后位置
          • 这不是 JPQL...(其中没有 TOP 1...)
          【解决方案5】:

          我不明白您为什么不存储简单的时间戳,而是使用两列来表示日期和时间。这使得运行您想要的选择变得更加困难。这是一个示例,如果时间戳可用,它应该如何工作(从查看 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 添加索引。

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

          【讨论】:

            【解决方案6】:

            如果 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)
            

            【讨论】:

              【解决方案7】:
              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();
              

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

              【讨论】:

                猜你喜欢
                • 2017-02-05
                • 2015-10-10
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2012-06-01
                相关资源
                最近更新 更多