计算给定时间段内有多少首条目和末尾条目相等

Count how many first and last entries in given period of time are equal

给定一个 table 结构如下:

id   | news_id(fkey)|    status      |    date
1          10          PUBLISHED      2016-01-10
2          20          UNPUBLISHED    2016-01-10
3          10          UNPUBLISHED    2016-01-12
4          10          PUBLISHED      2016-01-15
5          10          UNPUBLISHED    2016-01-16
6          20          PUBLISHED      2016-01-18
7          10          PUBLISHED      2016-01-18
8          20          UNPUBLISHED    2016-01-20
9          30          PUBLISHED      2016-01-20
10         30          UNPUBLISHED    2016-01-21

我想统计不同的新闻,在给定的时间段内,第一个和最后一个状态相等(并且状态等于查询中给定的)

因此,对于此 table 从 2016-01-01 到 2016-02-01 的查询将 return:

注意 news_id = 30 没有出现在结果中,因为他的 first/last 状态是相反的。

我已经使用以下查询完成了该操作:

SELECT count(*) FROM
(
    SELECT DISTINCT ON (news_id)
    news_id, status as first_status
    FROM news_events
    where date >= '2015-11-12 15:01:56.195'
    ORDER BY news_id, date
) first
JOIN (
    SELECT DISTINCT ON (news_id)
    news_id, status as last_status
    FROM news_events
    where date >= '2015-11-12 15:01:56.195'
    ORDER BY news_id, date DESC

) last
using (news_id)
where first_status = last_status
and first_status = 'PUBLISHED'

现在,我必须将查询转换为 SQL 我们内部的 Java 框架,不幸的是它不支持子查询,除非使用 EXISTSNOT EXISTS。有人告诉我将查询转换为使用 EXISTS 子句的查询(如果可能的话)或尝试寻找另一种解决方案。然而,我一无所知。有人可以帮我做吗?

编辑:正如我现在被告知的那样,问题不在于我们的框架,而在于 Hibernate - 如果我理解正确,"you cannot join an inner select in HQL" (?)

不确定这是否能正确解决您的问题,因为它更像是一种解决方法。但考虑到以下几点:

新闻需要发布才能"unpublished"。因此,如果您为每个 "published" 加 1 并为每个 "unpublished" 减 1,如果第一个和最后一个是 "published",您的余额将为正(或准确地说是 1)。如果未发布的数量与已发布的数量一样多,那么它将为 0,如果未发布的数量多于已发布的数量(逻辑上不可能是这种情况,但显然可能会出现,因为您在 'published' 的查询中设置了日期阈值可能发生在之前)。

您可以使用此查询来找出:

SELECT SUM(CASE status WHEN 'PUBLISHED' THEN 1 ELSE -1 END) AS 'publishbalance'
FROM news_events
WHERE date >= '2015-11-12 15:01:56.195'
GROUP BY news_id

首先,子查询是SQL的重要组成部分。禁止使用它们的框架是一个糟糕的框架。

但是,"first" 和 "last" 可以用 NOT EXISTS 表示:如果不存在相同 news_id 和日期范围的较早或较晚的条目。

select count(*)
from mytable first
join mytable last on last.news_id = first.news_id
where date between @from and @to
and not exists
(
  select *
  from mytable before_first
  where before_first.news_id = first.news_id
  and before_first.date < first.date
  and before_first.date >= @from
)
and not exists
(
  select *
  from mytable after_last
  where after_last.news_id = last.news_id
  and after_last.date > last.date
  and after_last.date <= @to
)
and first.status = @status
and last.status = @status;

不存在救援:

SELECT ff.id ,ff.news_id ,ff.status , ff.zdate AS startdate
        , ll.zdate AS enddate
FROM newsflash ff
JOIN newsflash ll
        ON ff.news_id = ll.news_id
        AND ff.status = ll.status
        AND ff.zdate < ll.zdate
        AND  NOT EXISTS (
                SELECT * FROM newsflash nx
                WHERE nx.news_id = ff.news_id
                AND nx.zdate >= '2016-01-01' AND nx.zdate < '2016-02-01'
                AND (nx.zdate < ff.zdate OR nx.zdate > ll.zdate)
                )
ORDER BY ff.id
        ;