【问题标题】:How to return a birthday from an SQL statement, given a person's age给定一个人的年龄,如何从 SQL 语句中返回生日
【发布时间】:2012-03-15 07:48:08
【问题描述】:

我正在尝试在 ASP.net 中创建一个过滤器,用户可以在其中选择某个年龄,并且 SQL 语句将根据“DOB”(出生日期)返回当前处于该年龄的所有用户字段。

因此,例如,假设我有一个变量age,当前包含 23。我在数据库中有一个名为“DOB”的字段,类型为“日期”。如何编写 SQL 语句来返回所有出生日期显示为 23 岁的记录? DOB 格式为 YYYY-MM-DD。

谢谢

【问题讨论】:

  • DOB字段的数据类型是什么?格式仅在它是文本字段时才重要,它肯定不应该是。
  • '日期'类型!编辑问题以反映这一点。
  • 你如何定义一个人是23岁?出生在24-Feb-1989?出生于1989?在24-Feb-1989 之前但在24-Feb-1988 之后出生?
  • @ypercube 大概是一个 23 岁的人,他的 23 岁生日是今天,或者一年前的今天。

标签: c# asp.net sql sql-server database


【解决方案1】:

我将假设数据库列和age 变量都保存日期/时间数据而不是字符串。我还将假设 [DOB] 值保证没有时间分量。

您的规范中缺少一个数据:参考日期。换句话说,给定 23 岁和一堆生日,您想知道在给定日期 哪些人是 23 岁。您可能会认为这将是当前日期,但在这里我们将其概括为一个变量。

1989 年 2 月 24 日出生的人今天 23 岁;以后出生的人更年轻。 1988 年 2 月 24 日或更早出生的人今天已年满 24 岁。因此,所需的范围是 1988 年 2 月 25 日到 1989 年 2 月 24 日。

DECLARE @age int
DECLARE @referenceDate date
DECLARE @rangeEnd date
DECLARE @rangeBegin date

SELECT @age = 23
SELECT @referenceDate = GETDATE()
            --2012-02-24
SELECT @rangeBegin = DATEADD(day, 1, DATEADD(year, -@age-1, @referenceDate))
            --1988-02-25
SELECT @rangeEnd = DATEADD(year, -@age, @referenceDate)
            --1989-02-24

-- EDIT: this expression is incorrect; thanks to ypercube for catching the bug
-- SELECT @rangeBegin = DATEADD(day, 1, DATEADD(year, -1, @rangeEnd))

SELECT * FROM <table> 
WHERE DOB BETWEEN @rangeBegin AND @rangeEnd

【讨论】:

  • +1 来自我。你解释了你是如何(以及什么)计算的,所以很容易调整这个代码。另外,查询将使用dob 列上的索引(如果可能)。
  • 迄今为止最好的,但仍然不能处理闰日。
  • 我认为应该是:SELECT @rangeBegin = DATEADD(day, 1, DATEADD(year, -@age-1, @referenceDate )) 和讨厌的闰年就可以了。
  • @Joe 使用 DATEADD 应该处理闰日,不是吗?
  • @ypercube 我看不出这会如何改变结果。
【解决方案2】:
WHERE YEAR(GETDATE() - DATEPART(dy, DOB) + 1) - YEAR(DOB) = 37

只需将 37 更改为 23 或更好地使用变量

这是一个你可以运行的例子

CREATE TABLE #test(DOB DATETIME)

INSERT #test VALUES('19701127')
INSERT #test VALUES('19741127')
INSERT #test VALUES('19740227')
INSERT #test VALUES('19761127')
INSERT #test VALUES('19761127')
INSERT #test VALUES('19701127')


SELECT * FROM #test
WHERE YEAR(GETDATE() - DATEPART(dy, DOB) + 1) - YEAR(DOB) = 37

1974-11-27 00:00:00.000
1974-02-27 00:00:00.000

你也可以使用这个更复杂的 WHERE 子句

 SELECT *
        FROM #test
        WHERE DATEDIFF(YEAR, DOB, GETDATE()) -
        CASE WHEN DATEPART(mm,DOB) > DATEPART(mm,GETDATE())
       OR (DATEPART(mm,DOB) = DATEPART(mm,GETDATE())
       AND DATEPART(dd,DOB) > DATEPART(dd,GETDATE()))
        THEN 1 ELSE 0 END = 37

【讨论】:

  • 这不适用于闰年。例如,出生于“2011-04-01”(非闰年)的人将被视为“2012-03-31”(闰年)一岁;早了一天。
【解决方案3】:

实现这一目标的另一种方法。

DECLARE @age int
DECLARE @dob1 date
DECLARE @dob2 date
SELECT @age = 23
SELECT @dob1 = DATEADD(year, -@age, getdate())
SELECT @dob2 = DATEADD(year, 1, @dob1)

SELECT * FROM <table> 
WHERE DOB BETWEEN @dob1 AND @dob2

【讨论】:

  • 除了 1989 年 2 月 24 日出生的人(今天 23 岁)之外,这将返回 1989 年 2 月 25 日至 1990 年 2 月 24 日之间出生的人,他们今天都 22 岁。
  • @phoog:这是对年龄的另一种定义。我猜不是很受欢迎,但是小孩(想要看起来更老)倾向于使用这个定义:)
  • 恕我直言,这比@SQLMenace 的回答更清楚;但是它并不完全正确:BETWEEN 是一个包容性运算符 - 你想要DOB &gt;= @dob1 and DOB &lt; @dob2。如果今天和出生日期都在闰日(2 月 29 日),它也不会正常工作。
【解决方案4】:

那些出生日期与今天相同的人,确切地说是@age 年前:

WHERE dob = DATEADD( year, - @age, GETDATE() ) 

【讨论】:

  • 谢谢,但有没有办法让它通用,即不只是今天出生?
  • @Sean:你的意思是要找到在1989(23 年)的任何日期出生的每个人?
  • 我试图返回数据库中所有 23 岁的人,而我在数据库中得到的只是他们的出生日期。
  • 2 月 24 日之前出生的人是 24 岁而不是 23 岁
  • SQLMenace:你什么意思?如果某人出生于1989-02-24,则正好是 23 岁(或 23 岁零一天,具体取决于您所在的时区)。
【解决方案5】:

如果DOB字段是日期字段,你可以做一些日期比较来得到你想要的。

SELECT user, DOB FROM yourtable 
WHERE MONTH(CURDATE())=MONTH(DOB) AND 
DAY(CURDATE())=DAY(DOB) AND YEAR(CURDATE())-YEAR(DOB)=23;

【讨论】:

  • 您假设它是 MySQL,但实际上它是 MS SQL Server。没有CURDATE(),但有GETDATE()
  • 不,这将返回所有今天庆祝 23 岁生日的人,而不是所有目前 23 岁的人。
猜你喜欢
  • 1970-01-01
  • 2010-10-01
  • 1970-01-01
  • 2022-08-22
  • 1970-01-01
  • 1970-01-01
  • 2020-11-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多