计算在给定时间段内有多少第一个和最后一个条目相等

时间:2016-01-22 10:47:38

标签: sql database hibernate postgresql hql

给出一个像这样的结构表:

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

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

因此,对于此表,2016-01-01至2016-02-01的查询将返回:

  • 1(WHERE status = 'PUBLISHED')因为news_id 10在第一个(2016-01-10)和最后一行(2016-01-18)都已发布
  • 1(WHERE status = 'UNPUBLISHED',因为news_id 20在第一行和最后一行都有UNPUBLISHED

注意news_id = 30没有出现在结果中,因为他的第一个/最后一个状态是相反的。

我使用以下查询完成了这项工作:

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中 - 如果我理解正确的话,"你不能加入HQL中的内部选择" (?)

3 个答案:

答案 0 :(得分:4)

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

新闻需要在“未发布”之前发布。因此,如果您为每个“已发布”添加1并为每个“未发布”减去1,则如果第一个和最后一个是“已发布”,则您的余额将为正(或准确为1)。如果你有未公布的未公布和否定,那么它将是0,如果它有未公布的数据而不是已公布的(在逻辑上不可能是这种情况,但显然可能会出现,因为你在查询中设置了一个日期阈值,其中'已发布'可能是之前发生过。)

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

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

答案 1 :(得分:2)

首先,子查询是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;

答案 2 :(得分:1)

没有拯救:

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
        ;