SQL年龄计算-准确的方法

时间:2019-06-04 08:08:10

标签: sql sql-server

我尝试了三种方法,所有方法都可以,但是得到不同的结果:

  1. SELECT @age = DATEDIFF(YY, x.BirthDate, x.LastVisitDate)
    
  2. SELECT @age = (CONVERT(int,CONVERT(char(8),x.LastVisitDate,112)) - CONVERT(char(8),x.BirthDate,112)) / 10000
    
  3. SELECT @age =  FLOOR(DATEDIFF(DAY, x.BirthDate , x.LastVisitDate) / 365.25)
    

第一个我得到63,第二个和第三个我得到62,哪个是正确的?

4 个答案:

答案 0 :(得分:1)

只需使用大型机时代的古老算法:

SELECT @age = (
           (YEAR(x.LastVisitDate) * 10000 + MONTH(x.LastVisitDate) * 100 + DAY(x.LastVisitDate))
          -
           (YEAR(x.BirthDate)* 10000 + MONTH(x.BirthDate) * 100 + DAY(x.BirthDate))
          ) / 10000

答案 1 :(得分:0)

一个人一年中的生日年龄是(岁-出生年份) 这就是带有yy参数的datediff的结果。如果他们还没有生日,那么您必须减去一年,这就是我的IIF所做的。

您已经发现,其他方法也存在缺陷。例如,我体验到/365.25天有时会在一个人的生日前后出错,并且如果他们出生于2月29日,这是一个额外的技巧

SELECT @age = DATEDIFF(YY, x.BirthDate, x.LastVisitDate) - 
    IIF(MONTH(x.LastVisitDate) < MONTH(x.BirthDate) 
                OR MONTH(x.LastVisitDate) = MONTH(x.BirthDate) AND DAY(x.LastVisitDate) < DAY(x.BirthDate) 
                                  , 1
                                  , 0
        )

答案 2 :(得分:0)

尝试使用此标量函数。 它带有三个参数。

开始日期和结束日期以及增加一天的额外选项。

该函数以“ YY MM DD”的形式返回结果。有几个例子

SELECT dbo.CalcDate(NULL, GETDATE(), 0); --> NULL
SELECT dbo.CalcDate(GETDATE(), GETDATE(), 0); --> 0 0 0
SELECT dbo.CalcDate(GETDATE(), GETDATE(), 1); ---> 0 0 1
SELECT dbo.CalcDate('20150101', '20161003', 0); ---> 1 9 2 
SELECT dbo.CalcDate('20031101', '20161003', 0); --->12 11 2
SELECT dbo.CalcDate('20040731', '20040601', 0); ---> 0 1 30 
SELECT dbo.CalcDate('20040731', '20040601', 1); ---> 0 2 0 

并且源代码在下面的代码段中列出。

CREATE FUNCTION [dbo].[CalcDate]
( 
                @dwstart datetime, @dwend datetime,@extraDay bit
)
RETURNS nvarchar(20)
BEGIN
    DECLARE @yy int;
    DECLARE @mm int;
    DECLARE @dd int;
    DECLARE @increment int;
SET @increment = 0;
    DECLARE @monthDay TABLE
    ( 
                            monthno int, monthdayno int
    );
    DECLARE @dStart AS datetime;
    DECLARE @dEnd AS datetime;
INSERT INTO @monthDay
    VALUES (1, 31);
INSERT INTO @monthDay
    VALUES (2, -1);
INSERT INTO @monthDay
    VALUES (3, 31);
INSERT INTO @monthDay
    VALUES (4, 30);
INSERT INTO @monthDay
    VALUES (5, 31);
INSERT INTO @monthDay
    VALUES (6, 30);
INSERT INTO @monthDay
    VALUES (7, 31);
INSERT INTO @monthDay
    VALUES (8, 31);
INSERT INTO @monthDay
    VALUES (9, 30);
INSERT INTO @monthDay
    VALUES (10, 31);
INSERT INTO @monthDay
    VALUES (11, 30);
INSERT INTO @monthDay
    VALUES (12, 31);
--The order of the arguments is not important
IF @dwStart > @dWEnd
BEGIN
SET @dStart = @dWEnd;
SET @dEnd = @dWStart;
    END;
ELSE
BEGIN
SET @dStart = @dWStart;
SET @dEnd = @dWEnd;
    END;
--

DECLARE @d1 AS INT;
SET @d1 = DAY(@dStart);
    DECLARE @d2 AS int;
SET @d2 = DAY(@dEnd);
    IF @d1 > @d2
    BEGIN
SET @increment = (SELECT
        monthdayno
    FROM @monthDay
    WHERE monthno = MONTH(@dStart));
    END;

IF @increment = -1
BEGIN
--Is it a leap year
SET @increment = (SELECT
        CASE
            WHEN ISDATE(CAST(YEAR(@dStart) AS CHAR(4)) + '0229') = 1 THEN 29
            ELSE 28
        END);
    END;

IF @increment != 0
BEGIN
SET @DD = DAY(@dEnd) + @increment - DAY(@dStart) + (CASE
    WHEN @extraDay = 1 THEN 1
    ELSE 0
END);
SET @increment = 1;
    END;
ELSE
BEGIN
SET @dd = DAY(@dEnd) - DAY(@dStart) + (CASE
    WHEN @extraDay = 1 THEN 1
    ELSE 0
END);
    END;
IF (MONTH(@dStart) + @increment) > MONTH(@dEnd)
BEGIN
SET @mm = MONTH(@dEnd) + 12 - (MONTH(@dStart) + @increment);
SET @increment = 1;
    END;
ELSE
BEGIN
SET @mm = MONTH(@dEnd) - (MONTH(@dStart) + @increment);
SET @increment = 0;
    END;
SET @yy = YEAR(@dEnd) - (YEAR(@dStart) + @increment);
    IF @dd >= 31
    BEGIN
SET @mm = @mm + 1;
SET @dd = @dd - 31;
    END;

IF @mm >= 12
BEGIN
SET @yy = @yy + 1;
SET @mm = @mm - 12;
    END;

RETURN (CONVERT(NVARCHAR(2), @yy) + ' ' + CONVERT(NVARCHAR(2), @mm) + ' ' + CONVERT(NVARCHAR(2), @dd));


END;

答案 3 :(得分:0)

如果您要某人的年龄,则取“年”之差,然后根据MMDD的顺序减去一个。所以:

select (year(x.LastVisitDate) - year(x.BirthDate) -
        (case when month(x.LastVisitDate) < month(x.BirthDate)
              then 1
              when month(x.LastVisitDate) = month(x.BirthDate) and
                   day(x.LastVisitDate) < day(x.BirthDate)
              then 1
              else 0
         end)
       ) as age

这对于for年和leap日应该是正确的,并且仅在某人的生日(或者如果生日是2月29日,然后在3月1日)上增加年龄。

您还可以使用MMDD表示并执行以下操作来表达case表达式:

        (case when ( month(x.LastVisitDate) * 100 + day(x.LastVisitDate) <
                      month(x.BirthDate) * 100 + day(x.BirthDate
                   )
              then 1
              then 1
              else 0
         end)

使用DATEDIFF()的方法根本不起作用(很容易),因为DATEDIFF()不在计算两个时间段之间的差,而是在它们之间的时间间隔数。

使用天数差除以365.25是一个近似值,并且在生日前后会自动消失。

使用日历规则(例如上述规则)应该会产生正确的结果。