2014-02-28 55 views
2

在我的Java Web應用程序中,我使用Postgresql,並且一些數據表在服務器中自動填充。在數據庫中,我有一個狀態表,如下圖所示:Postgresql在選定的日期和狀態之間選擇數據

enter image description here

我想選擇與所選擇的日期,並在車輛仍保持連接狀態之間的車輛數據。簡單地說,我想要選擇上表中綠色的數據,這意味着當首次連接= true時,我確實需要數據,而當連接=上一次連接=真時,數據連接= false。我試圖寫一個SQL語句,但我無法獲得所需的數據。

我所做的是:

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

我怎麼能獲得所請求的數據?

回答

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

+0

你的回答很有效。它以期望的順序給出所需的數據。但是,我想要檢索STATUS表中的所有字段。此外,這個答案是否適用於Hibernate?謝謝。 – nudaStck

+0

如果該表的列數多於所示的4,那麼只需將'SELECT statusId,vehicleId,connected,date'(兩次)替換爲所需的列。不知道Hibernate,對不起。 –

+0

非常感謝您的回答。我將發佈另一個與Hibernate相關的問題。 – nudaStck

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

+0

@zamansafari你可以在年底改變'ORDER BY'滿足您的需求。 –

+0

你的答案很有效,但數據的順序是混合的。其實我的狀態表有更多的功能。我想檢索包含所有列的選定行,檢索到的數據應由vehicleId進行排序,並按ASC順序進行排序。先謝謝你。 – nudaStck

+0

@GarethD,你最後的回答很好,很快。數據的順序是混合的。我改變了ORDER BY命令;但是,我無法獲得所需的數據順序。它應該按ASC順序通過車輛編號和日期進行排序。我也想檢索表的所有字段。 – nudaStck

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'; 
  • 滯後(狀態)將返回在它之前的狀態(我們的分區中)。

  • 分區由vehicleid(與由日期的順序排列)保證了我們的滯後()返回同一vehicleid的行。

window functions列表以獲得更多關於滯後()和相關功能。

+0

+1的順序首先出現+1比我的簡單。我可能有點想到它! – GarethD