给出一个像这样的结构表:
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的查询将返回:
WHERE status = 'PUBLISHED'
)因为news_id 10在第一个(2016-01-10)和最后一行(2016-01-18)都已发布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框架,遗憾的是它不支持子查询,除非使用EXISTS
或NOT EXISTS
。我被告知使用EXISTS
子句将查询转换为一个(如果可能的话)或尝试寻找另一个解决方案。然而,我是无能为力的。有人可以帮我这么做吗?
答案 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
;