假设一个简单的表包含两个用户的状态事件。 status_id为1使它们“活动”,其他任何东西都使它们处于非活动状态。 我需要找出所有在一年之内>> 处于非活动状态的用户,例如2015-05-01(不包括该日期)。
CREATE TABLE user_status(
user_id INT,
status_id INT,
date_assigned VARCHAR(10) );
INSERT INTO user_status( user_id, status_id, date_assigned)
VALUES
(1234, 1, '2015-01-01'), -- 1234 becomes active (status id = 1)
(1234, 2, '2015-07-01'), -- 1234 de-activated for reason 2
(5678, 1, '2015-02-01'), -- 5678 becomes active (status id = 1)
(5678, 3, '2015-04-01'), -- 5678 de-activated for reason 3
(5678, 5, '2015-06-01'); -- 5678 de-activated for reason 5
使用查询
SELECT t1.*
FROM user_status t1
WHERE t1.date_assigned = (SELECT MIN(t2.date_assigned) -- the first occurrence
FROM user_status t2
WHERE t2.user_id = t1.user_id -- for this user
AND t2.status_id <> 1 -- where status not active
AND t2.date_assigned BETWEEN -- within 1 yr of given date
'2015-05-01' + INTERVAL 1 DAY -- (not including that date)
AND
'2015-05-01' + INTERVAL 1 YEAR
)
我可以得到结果
user_id status_id date_assigned
1234 2 2015-07-01
5678 5 2015-06-01
这是正确的,但用户5678不应该在那里,因为尽管他们在日期范围内有非活动事件,但他们在所需日期范围开始之前已经处于非活动状态,因此 不活动在这个范围内。
我需要在我的查询中添加一点“只显示那些有非活动事件的用户和,其中该用户的上一个status_id为1,即他们在非活动事件发生的时间。
任何人都可以帮我解决语法问题吗? 见SQL fiddle
答案 0 :(得分:1)
您可以在查询中添加NOT EXISTS
:
SELECT t1.*
FROM user_status t1
WHERE t1.date_assigned = (SELECT MIN(t2.date_assigned) -- the first occurance
FROM user_status t2
WHERE t2.user_id = t1.user_id -- for this user
AND t2.status_id <> 1 -- where status not active
AND t2.date_assigned BETWEEN -- within 1 yr of given date
'2015-05-01' + INTERVAL 1 DAY -- (not including that date)
AND
'2015-05-01' + INTERVAL 1 YEAR
)
AND NOT EXISTS (SELECT 1 -- such a record should not exist
FROM user_status t3
WHERE t3.user_id = t1.user_id -- for this user
AND t3.status_id <> 1 -- where status is not active
AND t3.date_assigned < -- before the examined period
'2015-05-01' + INTERVAL 1 DAY )
修改强>
您可以使用以下查询,该查询也考虑具有多个激活日期的情况:
SELECT *
FROM user_status
WHERE (user_id, date_assigned) IN (
-- get last de-activation date
SELECT t1.user_id, MAX(t1.date_assigned)
FROM user_status AS t1
JOIN (
-- get last activation date
SELECT user_id, MAX(date_assigned) AS activation_date
FROM user_status
WHERE status_id = 1
GROUP BY user_id
) AS t2 ON t1.user_id = t2.user_id AND t1.date_assigned > t2.activation_date
GROUP BY user_id
HAVING MAX(date_assigned) BETWEEN '2015-05-01' + INTERVAL 1 DAY AND '2015-05-01' + INTERVAL 1 YEAR AND
MIN(date_assigned) > '2015-05-01' + INTERVAL 1 DAY)
答案 1 :(得分:1)
自我加入解决方案:在日期标准中找到最小值(第一次更改状态):
select a.user_id,b.status_id,max(b.date_assigned)
from user_status a
inner join user_status b
on a.user_id=b.user_id
and a.date_assigned <b.date_assigned
where b.status_id >1 and a.status_id=1
group by a.user_id,b.status_id
having max(b.date_assigned)> '2015-05-01'
and max(b.date_assigned) <='2016-05-01'