用于查找" LAST"的MySQL查询行,基于两个字段

时间:2014-03-15 09:33:46

标签: mysql sql

我有以下MySQL表来记录学生的注册状态变化:

CREATE TABLE `pupil_registration_statuses` (
`status_id` INT(11) NOT NULL AUTO_INCREMENT,
`status_pupil_id` INT(10) UNSIGNED NOT NULL,
`status_status_id` INT(10) UNSIGNED NOT NULL,
`status_effectivedate` DATE NOT NULL,
PRIMARY KEY (`status_id`),
INDEX `status_pupil_id` (`status_pupil_id`)
)
COLLATE='utf8_general_ci'
ENGINE=MyISAM;

示例数据:

INSERT INTO `pupil_registration_statuses` (`status_id`, `status_pupil_id`, `status_status_id`, `status_effectivedate`) VALUES
    (1, 123, 1, '2013-05-06'),
    (2, 123, 2, '2014-03-15'),
    (3, 123, 5, '2013-03-15'),
    (4, 123, 6, '2013-05-06'),
    (5, 234, 2, '2013-02-02'),
    (6, 234, 4, '2013-04-17'),
    (7, 345, 2, '2014-02-01'),
    (8, 345, 3, '2013-06-01');

可能会插入状态,因此日期序列不一定遵循相同的ID序列。

例如:status_id 1的日期可能是2013-05-06,但status_id 3的日期可能是2013-03-15。

但是,

status_id值在任何特定日期内都是连续的。因此,如果学生的注册状态在一天内多次更改,那么最后一行将反映他们在该日期的状态。

有必要在特定日期找出特定学生的注册状态。以下查询适用于个别学生:

SELECT * 
FROM pupil_registration_statuses 
WHERE status_pupil_id = 123
    AND status_effectivedate <= '2013-05-06'
ORDER BY status_effectivedate DESC, status_id DESC
LIMIT 1;

这将返回预期的status_id = 4

但是,我现在需要发出一个(单个)查询来返回特定日期所有学生的状态。

建议使用以下查询,但不会在一天内遵守&#34;最后status_id&#34;要求:

SELECT *
FROM pupil_registration_statuses prs
    INNER JOIN (SELECT status_pupil_id, MAX(status_effectivedate) last_date
        FROM pupil_registration_statuses
        WHERE status_effectivedate <= '2013-05-06'
        GROUP BY status_pupil_id) qprs ON prs.status_pupil_id = qprs.status_pupil_id AND prs.status_effectivedate = qprs.last_date;

但是,此查询为pupil 123返回2行。

修改

为了澄清,如果输入是日期'2013-05-06',我希望从查询中获得第4行和第6行。

http://sqlfiddle.com/#!2/68ee6/2

3 个答案:

答案 0 :(得分:1)

这就是你要追求的吗?

SELECT a.*
  FROM pupil_registration_statuses a
  JOIN
     ( SELECT prs.status_pupil_id
            , MIN(prs.status_id) min_status_id
         FROM pupil_registration_statuses prs
         JOIN 
            ( SELECT status_pupil_id
                   , MAX(status_effectivedate) last_date
                FROM pupil_registration_statuses
               WHERE status_effectivedate <= '2013-05-06'
               GROUP
                  BY status_pupil_id
            ) qprs 
           ON prs.status_pupil_id = qprs.status_pupil_id 
          AND prs.status_effectivedate = qprs.last_date
        GROUP
           BY prs.status_pupil_id
     ) b
    ON b.min_status_id = a.status_id;

http://sqlfiddle.com/#!2/68ee6/7

(顺便说一句,对于这类问题,这是一个丑陋且无证件的黑客攻击:

SELECT x.* FROM (SELECT * FROM prs WHERE status_effectivedate <= '2013-05-06' ORDER BY status_pupil_id, status_effectivedate DESC, status_id)x GROUP BY status_pupil_id;

......但我没有告诉你那个! ;))

答案 1 :(得分:0)

我已经更改了where子句,请尝试一下。

SELECT *
    FROM pupil_registration_statuses prs
        INNER JOIN (SELECT status_pupil_id, MAX(status_effectivedate) last_date
            FROM pupil_registration_statuses
            WHERE Datediff(status_effectivedate, '2013-05-06') <= 0
            GROUP BY status_pupil_id) qprs ON prs.status_pupil_id = qprs.status_pupil_id AND prs.status_effectivedate = qprs.last_date;

修改

试试这个

SELECT *
    FROM 

        (
            select status_pupil_id,max(status_id) as status_id from pupil_registration_statuses innr
            --where Datediff(dd,status_effectivedate, '2013-05-06') >= 0
            group by status_pupil_id

        )as ca 
        inner join pupil_registration_statuses prs on prs.status_id = ca.status_id
where   Datediff(dd,prs.status_effectivedate, '2013-05-06') >= 0

答案 2 :(得分:0)

如果我理解正确,你想......

1)每人一排。

2)从您手动输入的特定日期获取状态更改。

3)从特定日期内获取最后一次状态更改。

如果这是正确的,您需要按日期排序的查询,然后按ID排序,只需distinct

SELECT DISTINCT on status_pupil_id *
FROM pupil_registration_statuses 
WHERE status_pupil_id = 123
    AND status_effectivedate <= '2013-05-06'
ORDER BY status_effectivedate DESC, status_id DESC