【问题标题】:Calculating and showing Age Column on Sql Server as (xx Years, xx months) [duplicate]在 Sql Server 上计算年龄列并将其显示为(xx 年,xx 个月)[重复]
【发布时间】:2012-03-16 08:35:35
【问题描述】:

可能重复:
How to calculate age in T-SQL with years, months, and days

我在 Sql Server 2005 上计算年龄时遇到问题。我有一个客户表,其日期为 birth column。我想要的是创建具有age column 的视图,而这个age column 应该通过从今天减去出生日期来显示person 的年龄(非常简单)。

我在这里找到了一些很好的资源,但我真正想要的是按年和月显示年龄。例如(47 岁,3 个月)。这意味着我想同时拥有年份和月份值,并且我想将string'years', 'yrs', 'y', 'months', 'mon', 'm', ...)添加到适当的值并将其显示为例如。 (25 years, 2 months)。 如果这个人的年龄只是3 months,它应该显示'3 months',而不是'0 years, 3 months'。

如果这个人的年龄是几年没有任何月份,它应该显示例如。 '5 years' 不是'5 years, 0 months'

哦,我已经使用 c# 完成了,但我想在 sql 视图上创建一个列,这样我就可以使用视图填充我的 gridview 而无需对我的 c# 代码进行任何计算。 如果有帮助,我可以在这里发布我的 c# 代码。 谢谢

【问题讨论】:

    标签: c# sql


    【解决方案1】:

    这是一个format_age 函数:

    CREATE FUNCTION format_age(
        @DOB datetime,
        @now datetime
    )
    RETURNS nvarchar(30)
    BEGIN
        DECLARE @years int, @months int;
        IF @DOB > @now RETURN N'not born yet';
        SET @years = DATEDIFF(year, @DOB, @now);
        IF MONTH(@DOB) * 100 + DAY(@DOB) > MONTH(@now) * 100 + DAY(@now)
            SET @years = @years - 1;
        SET @months = DATEDIFF(month, DATEADD(year, @years, @DOB), @now);
        IF DAY(@DOB) > DAY(@now)
            SET @months = @months - 1;
        RETURN CASE
            WHEN @years = 0 THEN CONVERT(nvarchar(30), @months) + N' months'
            WHEN @months = 0 THEN CONVERT(nvarchar(30), @years) + N' years'
            ELSE CONVERT(nvarchar(30), @years) + N' years, ' +
                CONVERT(nvarchar(30), @months) + N' months'
        END;
    END
    GO
    

    这里有一些测试用例:

    SELECT '2011-02-16' AS dt, dbo.format_age('2011-02-16', '2012-03-16') AS age UNION
    SELECT '2011-03-16',       dbo.format_age('2011-03-16', '2012-03-16')        UNION
    SELECT '2011-03-17',       dbo.format_age('2011-03-17', '2012-03-16')        UNION
    SELECT '2012-03-16',       dbo.format_age('2012-03-16', '2012-03-16')        UNION
    SELECT '2012-03-17',       dbo.format_age('2012-03-17', '2012-03-16')
    

    结果如下*

    | dt          | age               |
    |-------------|-------------------|
    | 2011-02-16  | 1 years, 1 months |
    | 2011-03-16  | 1 years           |
    | 2011-03-17  | 11 months         |
    | 2012-03-16  | 0 months          |
    | 2012-03-17  | not born yet      |
    

    *参考日期为2012-03-16

    【讨论】:

    • 在 sql server management studio 上执行查询时显示此错误。消息 139,级别 15,状态 1,过程 format_age,第 0 行无法将默认值分配给局部变量。消息 137,级别 15,状态 2,过程 format_age,第 10 行 必须声明标量变量“@years”。消息 139,级别 15,状态 1,过程 format_age,第 0 行无法将默认值分配给局部变量。消息 137,级别 15,状态 2,过程 format_age,第 13 行 必须声明标量变量“@months”。消息 137,级别 15,状态 2,过程 format_age,第 15 行必须声明标量变量“@years”。
    • 在 SQL Server 2008 中引入了使用 DECLARE 语句分配值。我更新了答案,将其拆分为单独的 DECLARESET
    • 在 SQL Server 2000 上测试过,似乎可以工作。
    【解决方案2】:

    我认为您应该考虑该解决方案的本地化问题(以及不同的标准来计算不同国家/地区的年龄)。如果你不关心,你可以:

    【讨论】:

    • 谢谢,我刚刚将我的 C# 代码转换为我在视图中使用的 Sql 函数。
    【解决方案3】:

    你需要这样的东西:

    SELECT *,
      case when DATEDIFF(MONTH, Birthday, GETDATE()) < 12
      then 
        CONVERT(nvarchar(16), DATEDIFF(MONTH, Birthday, GETDATE())) + ' months'
      else 
        CONVERT(nvarchar(16), DATEDIFF(YEAR, Birthday, GETDATE())) + ' years, ' + 
        CONVERT(nvarchar(16), DATEDIFF(MONTH, Birthday, GETDATE()) % 12 ) + ' months'
      end 
    FROM dbo.CUSTOMER
    

    【讨论】:

    • 这也不错,但有时会给出错误的答案。
    【解决方案4】:

    可能是这样的:

    测试数据

    DECLARE @tbl TABLE(birthDay DATETIME)
    INSERT INTO @tbl
    VALUES
        ('2004-04-05'),
        ('2001-02-05')
    

    查询

    ;WITH Years
    AS
    (   
        SELECT
            DATEDIFF(yy, tbl.birthDay, GETDATE()) - CASE WHEN (MONTH(tbl.birthDay) > MONTH(GETDATE())) OR (MONTH(tbl.birthDay) = MONTH(GETDATE()) AND DAY(tbl.birthDay) > DAY(GETDATE())) THEN 1 ELSE 0 END AS Years,
            tbl.birthDay
        FROM
            @tbl AS tbl 
    ), BithDayWithMonth
    AS
    (
        SELECT
            Years.Years,
            DATEDIFF(m, years.tmp, GETDATE()) - CASE WHEN DAY(Years.birthDay) > DAY(GETDATE()) THEN 1 ELSE 0 END AS Months
        FROM
            (
                SELECT
                    DATEADD(yy, Years.Years, Years.birthDay) AS tmp,
                    Years.Years,
                    Years.birthDay
                FROM
                    Years
            ) AS years
    )
    SELECT
        (CASE WHEN BithDayWithMonth.Years=0 THEN '' ELSE CAST(BithDayWithMonth.Years AS VARCHAR(10))+' years' END)+
        (CASE WHEN BithDayWithMonth.Months=0 THEN '' ELSE (CASE WHEN NOT BithDayWithMonth.Years=0 THEN ', ' ELSE '' END) +
        CAST(BithDayWithMonth.Years AS VARCHAR(10))+' months' END)
    FROM
        BithDayWithMonth
    

    【讨论】:

    • 查询成功执行,但有一些不规则的值,例如 24 年 24 个月(现在使用 2012 年 3 月 17 日,出生日期使用 1987 年 3 月 20 日)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-09-25
    • 1970-01-01
    • 1970-01-01
    • 2019-12-12
    • 1970-01-01
    • 2010-09-08
    相关资源
    最近更新 更多