在患者数据库中引入“年龄”类别

Hat*_*azy 5 database-design

我想在与患者相关的数据库中执行以下操作:

  • 当患者插入他的生日时,它会显示他的年龄类别:婴儿、儿童、成人、老人...等,以帮助我对我的患者进行分类
  • 如何将生日转换为年龄类别?
  • 如何设计那个年龄段?

Kev*_*sel 9

其中一些取决于您的特定数据库实现。然而,一般的部分是年龄类别的概念。这是一个实现,使用 ID 作为代理键并编写为与 SQL Server 一起使用(这意味着您可能需要稍微更改语法以使其与其他产品一起使用):

CREATE TABLE dbo.AgeCategory
(
    ID tinyint identity(1,1) NOT NULL,
    MinimumAge tinyint NOT NULL,
    Name varchar(20) NOT NULL
);
ALTER TABLE dbo.AgeCategory ADD CONSTRAINT [PK_AgeCategory] PRIMARY KEY(ID);
CREATE UNIQUE INDEX [IX_MinimumAge] ON dbo.AgeCategory(MinimumAge) INCLUDE(Name);

INSERT INTO dbo.AgeCategory(MinimumAge, Name) values
(0, 'Newborn'),
(1, 'Infant'),
(2, 'Toddler'),
(5, 'Child'),
(12, 'Adolescent'),
(18, 'Adult'),
(30, 'Some marker'),
(40, 'Something else'),
(50, '50+'),
(65, 'Retiree'),
(90, 'Amazing');
Run Code Online (Sandbox Code Playgroud)

我已经用样本年龄和类别填充了它。下面是如何使用此表的示例。我将使用出生日期填充 Person 表,然后查询以查找他们的年龄类别。

这是示例数据:

CREATE TABLE dbo.Person
(
    ID int identity(1,1) NOT NULL,
    Name varchar(50) NOT NULL,
    DateOfBirth datetime NOT NULL
);

insert into dbo.Person(Name, DateOfBirth) values
('Bob', '1983-01-08'),
('Mary', '1976-05-05'),
('Jane', '1960-04-01'),
('Tony', '2012-08-16'),
('Marcy', '1955-06-11'),
('Carl', '1930-12-24'),
('Joseph', '1918-11-11');
Run Code Online (Sandbox Code Playgroud)

这是查询:

with people as
(
    select
        Name,
        DateOfBirth,
        datediff(day, dateofbirth, current_timestamp) / 365.25 as YearsOld
    from
        dbo.Person p
)
select
    p.Name,
    p.DateOfBirth,
    p.YearsOld,
    a.MinimumAge,
    a.Name as AgeCategory
from
    people p
    cross apply
    (
        select top 1
            ac.MinimumAge,
            ac.Name
        from 
            dbo.AgeCategory ac
        where
            ac.MinimumAge < p.YearsOld
        order by
            ac.MinimumAge desc      
    ) a;
Run Code Online (Sandbox Code Playgroud)

请注意,此查询适用于 SQL Server,但我不能保证任何其他产品的语法都相同(或者这是解决 SQL Server 以外的任何产品的此问题的相对有效的方法)。我们正在做的是根据出生日期计算年龄。然后,我们可以使用 CROSS APPLY 函数将其应用于年龄类别表。这将返回特定行的一个最佳年龄类别。

请注意,您可以将 AgeCategory 表修改为具有两个年龄值:MinimumAge 和 MaximumAge。这将摆脱 cross apply 语句并用 INNER JOIN 替换它,但缺点是你可能会得到重叠的行:如果你的最小年龄为 10 岁,最大年龄为 20 岁,然后另一行与最小年龄为 15 岁,最大年龄为 25 岁,对于 15 岁到 20 岁之间的每个人,您将有两个结果。单项表摆脱了这个问题,而无需引入触发器或数据检查,除了年龄列上的唯一索引,但在数据集足够大的情况下,性能可能会更高。

  • 这是一个公平的观点。大约有一半的时间我会将最小和最大年龄分开(因为我知道我是唯一一个定义这些类别的人),但今天早上我感觉整个 Celko。:-) (2认同)

孔夫子*_*孔夫子 9

对于SQL SERVER,添加此列的一种非常简单的方法是作为计算列,由于 CURRENT_TIMESTAMP 依赖性,这将是不确定的。

alter table PATIENT add AgeCategory as
    CASE
    WHEN DateAdd(Year,1,DOB) > Current_Timestamp then 'infant'
    WHEN DateAdd(Year,4,DOB) > Current_Timestamp then 'toddler'
    WHEN DateAdd(Year,10,DOB) > Current_Timestamp then 'children'
    WHEN DateAdd(Year,14,DOB) > Current_Timestamp then 'tween'
    WHEN DateAdd(Year,18,DOB) > Current_Timestamp then 'teenager'
    WHEN DateAdd(Year,65,DOB) > Current_Timestamp then 'adult'
    ELSE 'elderly'
    END;
Run Code Online (Sandbox Code Playgroud)

即对于这个表:

CREATE TABLE PATIENT
(
    ID integer primary key,
    FullName varchar(255) NOT NULL,
    DOB datetime NOT NULL
);

insert into PATIENT(ID, FullName, DOB) values
    (1, 'John Doe', '1900-01-01'),
    (2, 'Jane Doe', '1960-02-03'),
    (3, 'Joe Public', '1990-05-06'),
    (4, 'Bob the Builder', '2007-08-09'),
    (5, 'Ecco the Dolphin', '2009-12-31'),
    (6, 'Foo', '2012-01-09'),
    (7, 'Bar', '2012-11-11');
Run Code Online (Sandbox Code Playgroud)

以下查询:

SELECT * FROM PATIENT
Run Code Online (Sandbox Code Playgroud)

返回:

ID          FullName             DOB                     AgeCategory
----------- -------------------- ----------------------- -----------
1           John Doe             1900-01-01 00:00:00.000 elderly
2           Jane Doe             1960-02-03 00:00:00.000 adult
3           Joe Public           1990-05-06 00:00:00.000 adult
4           Bob the Builder      2007-08-09 00:00:00.000 children
5           Ecco the Dolphin     2009-12-31 00:00:00.000 toddler
6           Foo                  2012-01-09 00:00:00.000 infant
7           Bar                  2012-11-11 00:00:00.000 infant
Run Code Online (Sandbox Code Playgroud)


对于所有其他 RDBMS,我可能会建议使用带有附加列的视图,因为AgeCategory无法持久化 - 从本质上讲,它可以根据时间在一个选择和下一个选择之间更改。每个 DBMS 的日期操作函数都不同,但模式是相似的。

例如,这是 SQLite ( SQLFiddle )的版本

create view PatientWithAgeCategory as
    select ID, FullName, DOB, 
        CASE
        WHEN Date(DOB, "+1 year") > Current_Timestamp then 'infant'
        WHEN Date(DOB, "+18 year") > Current_Timestamp then 'children'
        WHEN Date(DOB, "+65 year") > Current_Timestamp then 'adult'
        ELSE 'elderly'
        END AgeCategory
    from Patient;
Run Code Online (Sandbox Code Playgroud)

  • 为什么需要触发器?你指的是哪个数据库管理系统?SQL Server 中的计算列不需要触发器。 (2认同)