如何在数据不完整时按出生和死亡日期对人员列表进行排序

时间:2015-03-28 22:29:42

标签: mysql sorting date

我有一份可能有或没有出生日期和/或死亡日期的人员名单。我希望能够按出生日期对它们进行有意义的分类 - 主观术语。

但是 - 如果他们没有出生日期但是他们有一个死亡日期,我想把它们整理到接近其他死亡人员的名单中。

我认识到这不是一个离散的操作 - 当他们的出生日期缺失时,有人应该去哪里。但我大部分时间都在寻找一种很好的近似值。

以下是我想要的示例列表:

Alice     1800     1830
Bob       1805     1845
Carol              1847
Don       1820     1846
Esther    1825     1860

在这个例子中,我很高兴Carol出现在Don之前或之后 - 这是我准备接受的歧义。重要的结果是Carol在相对于她的死亡日期的列表中被排序为死亡日期,而不是按出生日期对死亡日期进行排序。

如果我合并或以其他方式将出生和死亡日期映射在一起,那么什么是行不通的。例如,ORDER BY birth_date, death_date会把卡罗尔放在以斯帖之后,这是我想的不合适的。

4 个答案:

答案 0 :(得分:1)

我认为你必须计算人们最终生活的平均年龄(对于那些同时有出生和死亡日期的人)。并且要么从死亡日期中减去它们,要么将它们添加到出生日期,以便那些没有另一个的人。

在一个查询中执行此操作可能效率不高,并且可能很难看,因为mysql没有窗口函数。您可能更好地预先计​​算平均生活年龄。但是,让我们尝试在一个查询中执行此操作:

SELECT   name, birth_date, death_date
FROM     people
ORDER BY COALESCE(
    birth_date,
    DATE_SUB(death_date, INTERVAL (
        SELECT AVG(DATEDIFF(death_date, birth_date))
        FROM people 
        WHERE birth_date IS NOT NULL AND death_date IS NOT NULL
    ) DAY)
)

答案 1 :(得分:1)

N.B。:我尝试过使用更大的数据集,但它并没有像我期望的那样完全正常工作。

尝试使用此查询(它需要id主键列):

SELECT * FROM people p
ORDER BY (
    CASE WHEN birth IS NOT NULL THEN (
        SELECT ord FROM (
                SELECT id, @rnum := @rnum + 1 AS ord
                FROM people, (SELECT @rnum := 0) r1
                ORDER BY (CASE WHEN birth IS NOT NULL THEN 0 ELSE 1 END), birth, death
            ) o1
        WHERE id = p.id
        ) ELSE (
        SELECT ord FROM (
                SELECT id, @rnum := @rnum + 1 AS ord
                FROM people, (SELECT @rnum := 0) r2
                ORDER BY (CASE WHEN death IS NOT NULL THEN 0 ELSE 1 END), death, birth
            ) o2
        WHERE id = p.id
        )
    END)
;

我所做的基本上是对数据集进行两次排序,一次按出生日期,然后按死亡日期排序。然后我使用这两个排序列表将最终顺序分配给原始数据集,首先从出生排序列表中选择位置,并在行没有出生日期时使用死亡排序列表中的位置。 / p>

以下是该查询的一些问题:

  • 我没有针对大量数据集运行它,所以我不能保证它可以用于任何数据集;
  • 我没有检查它的性能,因此在大型数据集上可能会非常慢。

这是我用来编写它的表,用MySQL 5.6.21测试过(我无法理解为什么,但SQL Fiddle拒绝使用Create script error我的脚本,所以我可以没有为你提供一个实例。

创建表:

CREATE TABLE `people` (
    `id` INT(11) NOT NULL AUTO_INCREMENT,
    `name` VARCHAR(50) NOT NULL,
    `birth` INT(11) NULL DEFAULT NULL,
    `death` INT(11) NULL DEFAULT NULL,
    PRIMARY KEY (`id`)
);

数据(我实际上稍微改变了你的数据):

INSERT INTO `people` (`name`, `birth`, `death`) VALUES ('Alice', 1800, NULL);
INSERT INTO `people` (`name`, `birth`, `death`) VALUES ('Bob', 1805, 1845);
INSERT INTO `people` (`name`, `birth`, `death`) VALUES ('Carol', NULL, 1847);
INSERT INTO `people` (`name`, `birth`, `death`) VALUES ('Don', 1820, 1846);
INSERT INTO `people` (`name`, `birth`, `death`) VALUES ('Esther', 1815, 1860);

答案 2 :(得分:0)

您可以使用子查询选择合适的生日来进行分类 然后是一个工会加入与生日的记录 例如:

select d1.name, null as birthdate, d1.deathdate, max(d2.birthdate) sort from
d as d1, d as d2
where d1.birthdate is null and d2.deathdate <=d1.deathdate
group by d1.name, d1.deathdate

union all

select name, birthdate, deathdate, birthdate from d
where birthdate is not null

order by 4

http://sqlfiddle.com/#!9/2d91c/1

答案 3 :(得分:-1)

不确定这是否有效,但值得一试(我无法在MySQL上测试),所以试着猜测:

order by case birth_date when null then death_date else birth_date end case