在给定时间段

时间:2016-07-29 13:54:16

标签: java database postgresql jpa

我有一个简单的表格,其中包含“读者”对象的状态历史记录。州可以是主动或非主动。现在我想有一个查询,它会选择所有读者,这些读者在给定时期内处于活动状态。下图显示了我的意思:带有绿色“生命线”的“读者”在显示的时间段内处于活动状态;所以它们将在查询中返回。

enter image description here

表格ReaderActivity看起来像这样(仅限示例,不匹配上图):

reader_id | state    | timestamp
 1        | ACTIVE   | 1467331201089
 2        | ACTIVE   | 1467332454545
 1        | INACTIVE | 1467348875254
 3        | ACTIVE   | 1467350416546
 1        | ACTIVE   | 1467351871123
 2        | INACTIVE | 1467352111545

当然,Reader映射到的reader_id个实体。

我需要有一个JPA查询,但我有问题,包括读者进入结果,在此期间内没有“上升边缘”(状态从INACTIVE变为ACTIVE)(在此期间已经有效)我们调查)。

我基本上看到了查询的部分内容:

  • 首先,选择所有具有上升沿的。这很简单:SELECT DISTINCT a.reader FROM ReaderActivity a WHERE a.timestamp >= :startTimestamp AND a.timestamp < :endTimestamp AND a.state = 'ACTIVE'
  • 其次,它应该附加到所有读者上面的列表中,其在句点开始之前具有最后状态ACTIVE。这是我没有得到正确答案:我尝试过(结合到第一个查询中):SELECT DISTINCT a.reader FROM ReaderActivity a WHERE a.timestamp >= :startTimestamp AND a.timestamp < :endTimestamp AND a.state = 'ACTIVE' or (SELECT aa.reader FROM ReaderActivity aa where aa.reader = a.reader AND aa.timestamp < :startTimestamp AND aa.state = 'ACTIVE' GROUP BY aa.reader ORDER BY max(aa.timestamp)) != null

这也返回上图中红色标记的阅读器,因为在子查询中使用AND aa.state = 'ACTIVE',我们已经过滤掉所有ACTIVE状态,因此最后一个当然是ACTIVE。我应该在开始时段之前选择最后一个状态,然后检查它是否为ACTIVE。但是如何?

有人能把我带到正确的路上吗? 提前致谢!

2 个答案:

答案 0 :(得分:1)

此查询应该这样做:

SELECT r.reader_id, r.timestamp
FROM ReaderActivity r 
WHERE   r.timestamp>=:start AND 
        r.timestamp<=:stop AND 
        r.state='ACTIVE' 

UNION ALL 

SELECT r1.reader_id, r1.timestamp
FROM ReaderActivity r1 
LEFT JOIN ReaderActivity r2 ON (r2.reader_id = r1.reader_id AND 
                                r2.timestamp<:start AND 
                                r2.timestamp>r1.timestamp)
WHERE   r1.timestamp<:start AND 
        r1.state='ACTIVE' AND 
        r2.id IS NULL 

UNION的fisrt部分选择在该时间段内激活的读者,而UNION的第二部分仅选择在该时间段之前激活的读者。

我没有测试过查询,你可能需要调整一下。

答案 1 :(得分:1)

查询的第一部分将根据需要将状态更改为活动状态的记录恢复为活动状态。查询的第二部分需要进行一些改进。

要做你想要的事情,你将不得不为每个reader_id带回最近的状态变化,直到&#34; startTimeStamp&#34;。然后,您将从中选择那些列为&#34; ACTIVE&#34;那个时候。

像...这样的东西。

Select a.reader_id 
From ReaderActivity a 
Where a.timeStamp in
( 
  Select max(b.timeStamp) 
  From ReaderActivity b 
  Where b.timestamp < :startTimeStamp 
  And b.reader_id = a.reader_id 
  Group By b.reader_id
)
and a.state = "ACTIVE"

此查询将返回在指定时间段开始时处于活动状态的所有[reader_id]。您可以在原始查询的where子句中运行它,或者您可以使用UNION将其附加到查询的末尾,并在整个混乱中运行Select Distinct(reader_id)。

从表中的组的最大值中选择对我来说总是有点古怪。但我希望这个查询有帮助!