在我的Java Web应用程序中,我使用Postgresql,并且一些数据表在服务器中自动填充。在数据库中,我有一个STATUS表,如下所示:
我想在所选日期和车辆保持连接的位置之间选择与车辆相关的数据。简单地说,我想在上表中选择绿色的数据,这意味着我在第一次连接时确实需要数据=真,而在最后连接=真后,连接时的数据=假。我试着编写一个sql语句但是我无法获得所需的数据。
我做的是:
select *from status where vehicleId='redcar' and
date >= '2014-02-28 00:00:00' and date <= '2014-02-28 23:59:59' and ...
我怎样才能获得所要求的数据?
答案 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 ;
进行测试