简体   繁体   English

MySQL:如何选择某个日期之前的最新日期的记录

[英]MySQL: how to select record with latest date before a certain date

Assume a simple table as follows containing status events for two users. 假定一个简单的表如下,其中包含两个用户的状态事件。 A status_id of 1 makes them 'active', anything else makes them de-active. status_id为1会使它们“处于活动状态”,其他任何条件会使它们处于非活动状态。 I need to find out all those users that became inactive within one year of, for example, 2015-05-01 (not including that date). 我需要找出所有在一年之内(例如,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

Using the query 使用查询

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 
                          )

I can get the result 我可以得到结果

user_id   status_id   date_assigned
 1234       2          2015-07-01
 5678       5          2015-06-01

This is sort of right but user 5678 should not be there because although they had an inactive event within the date range, they were already inactive before the desired date range began and so did not become inactive within that range. 这样做是正确的,但用户5678不应在那里,因为尽管他们在日期范围内有不活动的事件,但他们在所需的日期范围开始之前已经处于不活动状态,因此在该范围内没有变得不活动。

I need to add a bit to my query along the lines of 'only show me those users who had an inactive event and where the previous status_id for that user was 1, ie they were active at the time the inactive event happened. 我需要在查询中添加以下内容:“仅向我显示那些具有非活动事件的用户, 并且该用户的先前status_id所在的位置为1,即他们在非活动事件发生时处于活动状态。

Can anyone help me to get the syntax correct? 谁能帮我弄清楚语法?
See SQL fiddle 请参阅SQL提琴

You can add NOT EXISTS to your query: 您可以在查询中添加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 )

Demo here 在这里演示

Edit: 编辑:

You can use the following query that also considers the case of having multiple activation dates: 您可以使用以下查询,该查询还考虑具有多个激活日期的情况:

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)

Self join solution : finding minimum ( the first time the status changed) within your date criteria: 自助加入解决方案:在您的日期条件内找到最低要求(第一次更改状态):

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'

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM