我有一个大表(> 30M行),其中包含某种交易的信息。有一列有交易的完整日期,有一列有用户的出生年份。
列是:
DATETIME类型的 trans_date
(例如:2006-02-20 00:00:00 )
birth
( ex:1970 )
我想要的是能够在where子句中计算交易中人的年龄。例如,2006年 - 1970年= 36.因此,1970年出生的人在交易当年是36岁。
这就是我想要做的事情(伪代码):
SELECT name FROM table WHERE (YEAR(trans_date) - birth) = '36'
这样我就可以获得交易当年该人36岁的所有记录。这可能吗?
答案 0 :(得分:2)
当您处理无符号类型并获得负值时,birth > year(trans_date)
会发生错误。
您可以通过强制签名结果来解决此问题(假设birth
是无符号值):
WHERE (YEAR(trans_date) - CAST(birth AS SIGNED)) = 36
此外,不要对文字编号使用引号 - 计算返回一个数字,您应该将其与数字进行比较,而不是字符串(将隐式转换为数字)。
MySQL手册指出
默认情况下,整数操作数之间的减法会产生UNSIGNED 结果,如果任何操作数是UNSIGNED
可以通过更改设置来控制:SET sql_mode = 'NO_UNSIGNED_SUBTRACTION
有关详细信息,请参阅this part of the documentation。
另请注意,years
的确定并不准确,因为您缺乏实际确定年龄所需的精确度(因为您将日期与年份进行比较,用户的实际出生日期可能是在trans_date之前或之后)。
答案 1 :(得分:1)
在这里使用YEAR()将是不精确的,因为它不能正确匹配部分年份/帐户,因为某人生日已经或尚未过去。
你可以对他们出生日期的整个部分与当前日期进行计算,但是由于MySQL必须对每一行进行计算而不能使用索引,因此这将是低效的。
最佳方法是计算目标“出生日期”并将列与之比较,以便您也可以在列上使用索引。
示例:
WHERE
trans_date
BETWEEN
DATE_SUB(CUR_DATE(), INTERVAL 36 YEAR)
AND
DATE_SUB(CUR_DATE(), INTERVAL 37 YEAR)
测试边缘情况(即生日之前,之日或之后1天的交易日期),以确保您正确匹配范围而不是关闭范围。