繁体   English   中英

SQL年龄计算-准确的方法

[英]SQL Age Calculation - Accurate way

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

  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,哪个是正确的?

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

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

一个人一年中的生日年龄是(year-BirthYear)这就是带有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
        )

尝试使用此标量函数。 它包含三个参数。

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

该函数以“ 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;

如果要某人的年龄,则取“年”之差,然后根据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,这是一个近似值,并且即将在生日那天结束。

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

暂无
暂无

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

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