Postgresql选择所选日期和状态之间的数据

时间:2014-02-28 10:34:05

标签: sql hibernate postgresql

在我的Java Web应用程序中,我使用Postgresql,并且一些数据表在服务器中自动填充。在数据库中,我有一个STATUS表,如下所示:

enter image description here

我想在所选日期和车辆保持连接的位置之间选择与车辆相关的数据。简单地说,我想在上表中选择绿色的数据,这意味着我在第一次连接时确实需要数据=真,而在最后连接=真后,连接时的数据=假。我试着编写一个sql语句但是我无法获得所需的数据。

我做的是:

select *from status where vehicleId='redcar' and 
date >= '2014-02-28 00:00:00' and date <= '2014-02-28 23:59:59' and ...

我怎样才能获得所要求的数据?

3 个答案:

答案 0 :(得分:2)

您可以使用window function

执行此操作

这样的事情:

with status_changes as(
        select
             id,
             vehicleid,
             connected,
             connected != lag(connected)
                 over (partition by vehicleid
                       order by date asc) as has_changed
         from STATUS
)
select
    id,
    vehicleid, 
    connected,
    date
from status_changes
where has_changed = true
      and vehicle = 'redcar'
      and date between '2014-02-28 00:00:00' and '2014-02-28 23:59:59';
  • 滞后(状态)将返回其前面的状态(在我们的分区内)。

  • 按车辆分区(按日期排序)确保我们的 lag()返回相同车辆的行。

有关 lag()及相关功能的更多信息,请参阅window functions列表。

答案 1 :(得分:1)

您可以使用Gaps and Islands逻辑执行此操作:

SELECT  VehicleID, Connected, MIN(Date) AS Date
FROM    (   SELECT  *,
                    DENSE_RANK() OVER(PARTITION BY VehicleID ORDER BY Date) - 
                        DENSE_RANK() OVER(PARTITION BY VehicleID, Connected ORDER BY Date) AS GroupingSet,
                    MIN(CASE WHEN Connected THEN Date END) OVER(PARTITION BY VehicleID) AS FirstConnected
            FROM    status
            WHERE   VehicleID = 'redcar'
            AND     date >= '2014-02-28 00:00:00' 
            AND     date < '2014-03-01 00:00:00'
        ) s
WHERE   Date > FirstConnected
GROUP BY VehicleID, Connected, GroupingSet

<强> Example on SQL Fiddle

如果您还需要检索StatusID,则需要添加更多排名功能,并且只选择第一行:

SELECT  StatusID,
        VehicleID, 
        Connected, 
        Date
FROM    (   SELECT  StatusID,
                    VehicleID, 
                    Connected, 
                    Date,
                    ROW_NUMBER() OVER(PARTITION BY VehicleID, Connected, GroupingSet ORDER BY Date) AS RowNumber
            FROM    (   SELECT  *,
                                DENSE_RANK() OVER(PARTITION BY VehicleID ORDER BY Date) - 
                                    DENSE_RANK() OVER(PARTITION BY VehicleID, Connected ORDER BY Date) AS GroupingSet,
                                MIN(CASE WHEN Connected THEN Date END) OVER(PARTITION BY VehicleID) AS FirstConnected
                        FROM    status
                        WHERE   VehicleID = 'redcar'
                        AND     date >= '2014-02-28 00:00:00' 
                        AND     date < '2014-03-01 00:00:00'
                    ) s
            WHERE   Date > FirstConnected
        ) s
WHERE   RowNumber = 1;

<强> Example on SQL Fiddle

或使用DISTINCT ON

SELECT  DISTINCT ON (VehicleID, Connected, GroupingSet) 
        StatusID, 
        VehicleID, 
        Connected, 
        Date
FROM    (   SELECT  *,
                    DENSE_RANK() OVER(PARTITION BY VehicleID ORDER BY Date) - 
                        DENSE_RANK() OVER(PARTITION BY VehicleID, Connected ORDER BY Date) AS GroupingSet,
                    MIN(CASE WHEN Connected THEN Date END) OVER(PARTITION BY VehicleID) AS FirstConnected
            FROM    status
            WHERE   VehicleID = 'redcar'
            AND     date >= '2014-02-28 00:00:00' 
            AND     date < '2014-03-01 00:00:00'
        ) s
WHERE   Date > FirstConnected
ORDER BY VehicleID, Connected, GroupingSet

<强> Example on SQL Fiddle

答案 2 :(得分:1)

WITH cte AS
  ( SELECT statusId, vehicleId, connected, date,
           (connected <> LAG(connected) OVER (PARTITION BY vehicleId 
                                              ORDER BY date)
           ) AS status_changed
    FROM status 
    WHERE vehicleId = 'redcar' 
      AND date >= DATE '2014-02-28' 
      AND date <  DATE '2014-02-28' + interval '1 day'
  ) 
SELECT statusId, vehicleId, connected, date
FROM cte
WHERE status_changed 
   OR connected AND status_changed IS NULL 
ORDER BY date ;

SQL-Fiddle

进行测试