
当你只需要日期值而不需要时间部分时应使用DATE类型。MySQL用'YYYY-MM-DD'格式检索和显示DATE值。支持的范围是'1000-01-01'到 '9999-12-31'。
TIMESTAMP列类型的属性不固定,取决于MySQL版本和服务器运行的SQL模式。这些属性将在本节后面描述。
可以使用任何常见格式指定DATETIME、DATE和TIMESTAMP值:
'YYYY-MM-DD HH:MM:SS'或'YY-MM-DD HH:MM:SS'格式的字符串。允许“不严格”语法:任何标点符都可以用做日期部分或时间部分之间的间割符。例如,'98-12-31 11:30:45'、'98.12.31 11+30+45'、'98/12/31 11*30*45'和'98@12@31 11^30^45'是等价的。
'YYYY-MM-DD'或'YY-MM-DD'格式的字符串。这里也允许使用“不严格的”语法。例如,'98-12-31'、'98.12.31'、'98/12/31'和'98@12@31'是等价的。
'YYYYMMDDHHMMSS'或'YYMMDDHHMMSS'格式的没有间割符的字符串,假定字符串对于日期类型是有意义的。例如,'19970523091528'和'970523091528'被解释为'1997-05-23 09:15:28',但'971122129015'是不合法的(它有一个没有意义的分钟部分),将变为'0000-00-00 00:00:00'。
'YYYYMMDD'或'YYMMDD'格式的没有间割符的字符串,假定字符串对于日期类型是有意义的。例如,'19970523'和'970523'被解释为 '1997-05-23',但'971332'是不合法的(它有一个没有意义的月和日部分),将变为'0000-00-00'。
YYYYMMDDHHMMSS或YYMMDDHHMMSS格式的数字,假定数字对于日期类型是有意义的。例如,19830905132800和830905132800被解释为 '1983-09-05 13:28:00'。
YYYYMMDD或YYMMDD格式的数字,假定数字对于日期类型是有意义的。例如,19830905和830905被解释为'1983-09-05'。
函数返回的结果,其值适合DATETIME、DATE或者TIMESTAMP上下文,例如NOW()或CURRENT_DATE。
无效DATETIME、DATE或者TIMESTAMP值被转换为相应类型的“零”值('0000-00-00 00:00:00'、'0000-00-00'或者00000000000000)。
对于包括日期部分间割符的字符串值,如果日和月的值小于10,不需要指定两位数。'1979-6-9'与'1979-06-09'是相同的。同样,对于包括时间部分间割符的字符串值,如果时、分和秒的值小于10,不需要指定两位数。'1979-10-30 1:2:3'与'1979-10-30 01:02:03'相同。
数字值应为6、8、12或者14位长。如果一个数值是8或14位长,则假定为YYYYMMDD或YYYYMMDDHHMMSS格式,前4位数表示年。如果数字 是6或12位长,则假定为YYMMDD或YYMMDDHHMMSS格式,前2位数表示年。其它数字被解释为仿佛用零填充到了最近的长度。
指定为非限定符字符串的值使用给定的长度进行解释。如果字符串为8或14字符长,前4位数表示年。否则,前2位数表示年。从左向右解释字符串内出现的各部分,以发现年、月、日、小时、分和秒值。这说明不应使用少于6字符的字符串。例如,如果你指定'9903',认为它表示1999年3月,MySQL将在你的表内插入一个“零”日期值。这是因为年和月值是99和03,但日部分完全丢失,因此该值不是一个合法的日期。但是,可以明显指定一个零值来代表缺少的月或日部分。例如,可以使用'990300'来插入值'1999-03-00'。
在一定程度上,可以将一个日期类型的值分配给一个不同的日期类型。但是,值可能会更改或丢失一些信息:
如果你为一个DATETIME或TIMESTAMP对象分配一个DATE值,结果值的时间部分被设置为'00:00:00',因为DATE值未包含时间信息。
如果你为一个DATE对象分配一个DATETIME或TIMESTAMP值,结果值的时间部分被删除,因为DATE值未包含时间信息。
记住尽管可以使用相同的格式指定DATETIME、DATE和TIMESTAMP值,不同类型的值的范围却不同。例如,TIMESTAMP值不能早于1970或晚于2037。这说明一个日期,例如'1968-01-01',虽然对于DATETIME或DATE值是有效的,但对于TIMESTAMP值却无效,如果分配给这样一个对象将被转换为0。
当指定日期值时请注意某些缺陷:
指定为字符串的值允许的非严格格式可能会欺骗。例如,值'10:11:12'由于‘:’间割符看上去可能象时间值,但如果用于日期上下文值则被解释为年'2010-11-12'。值'10:45:15'被转换为'0000-00-00'因为'45'不是合法月。
在非严格模式,MySQL服务器只对日期的合法性进行基本检查:年、月和日的范围分别是1000到9999、00到12和00到31。任何包含超出这些范围的部分的日期被转换成'0000-00-00'。请注意仍然允许你保存非法日期,例如'2002-04-31'。要想确保不使用严格模式时日期有效,应检查应用程序。
在严格模式,非法日期不被接受,并且不转换。
包含两位年值的日期会令人模糊,因为世纪不知道。MySQL使用以下规则解释两位年值:
00-69范围的年值转换为2000-2069。
70-99范围的年值转换为1970-1999。
背景:1)mysql:Ver 14.12 Distrib 5.0.45, for Win32 (ia32)
2)mysql odbc驱动:3.51.22
3)vs2005
4)客户端用ado,odbc驱动连接mysql数据库
5)表tb_5100定义如下:
CREATE TABLE `tb_5100` (
`account_id` BIGINT(20) NOT NULL,
`service_id` INT(11) NOT NULL,
`f002d_5105` DATE NOT NULL,
`object_id` INT(11) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`object_id`)
) ENGINE=INNODB DEFAULT CHARSET=gbk
object_id字段AUTO_INCREMENT(自增长)
f002d_5105字段date类型,不能为空
问题:
开启一个事务
往tb_5100表插入一条记录,f002d_5105为空或者''(违反非空约束)
获取新记录的自增长字段object_id的值
根据自增长字段object_id查询新记录查不出来
提交事务
记录已经插入到数据库中,用mysql客户端工具可以查询出记录。
示例代码如下所示:
pdbor->BeginTrans()
string sql = "INSERT INTO tb_5100(account_id,service_id,f002d_5105) VALUES(10068,300,'')"
if( !pdbor->Execute(adCmdText,sql.c_str()) ){
pdbor->RollbackTrans()
return -1
}
///<获得自增长字段值
unsigned __int64 service_serial
if( pdbor->GetDBExt()->GetLastID(service_serial,1,"") ){
pdbor->RollbackTrans()
return -2
}
sql = LogMsg("SELECT * FROM tb_5100 where object_id=%d",service_serial)
CRecordset *prs = pdbor->Query(adCmdText,sql.c_str())
if( prs == NULL ){
pdbor->RollbackTrans()
return -3
}
if( prs->IsEof() ){
pdbor->RollbackTrans()
return -4///<查询不出来,函数返回-4
}
pdbor->CommitTrans()
return 0
经多次实验,
将f002d_5105字段改为允许为NULL,记录可以成功插入,在事务内,可以查询出新记录。
将数据库模式设置为STRICT_TRANS_TABLES严格模式(修改my.ini,在[mysqld]段,设置sql-mode="STRICT_TRANS_TABLES"),insert失败。
分析:
导致问题的原因为日期型字段f002d_5105数据非法的问题。新记录插入后,f002d_5105字段的值为'0000-00-00',为非法的日期型数据。MySQL是允许无效数据的存在的。详见http://it.china-b.com/sjk/mysql/20090828/179324_1.html(mysql中对无效数据的约束)。
而由于非法数据,导致同一个事务内能插入成功,但查询不来的问题,确实不解,这可能跟驱动有关,但只是个猜测。
解决此问题的办法应该是避免出现无效数据,应该使用严格的约束模式,即STRICT_TRANS_TABLES。参见http://www.zhixing123.cn/php/MYSQL%20STRICT_TRANS_TABLES.html。
参考:
http://it.china-b.com/sjk/mysql/20090828/179324_1.html
http://www.zhixing123.cn/php/MYSQL%20STRICT_TRANS_TABLES.html
在MySQL5.0.2之前,MySQL对非法或不当值并不严厉,而且为了数据输入还会强制将它们变为合法值。在MySQL5.0.2和更高版本中,保留了以前的默认行为,但你可以为不良值选择更传统的处理方法,从而使得服务器能够拒绝并放弃出现不良值的语句。本节介绍了MySQL的默认行为(宽大行为),新的严格的SQL模式,以及它们的区别。如果你未使用严格模式,下述情况是真实的。如果将“不正确”的值插入到列,如将NULL值插入非NULL列,或将过大的数值插入数值列,MySQL会将这些列设置为“最可能的值”,而不是生成错误信息。如果试图将超范围的值保存到数值列,MySQL服务器将保存0(最小的可能值)取而代之,或最大的可能值。对于字符串,MySQL或保存空字符串,或将字符串尽可能多的部分保存到列中。如果打算将不是以数值开头的字符串保存到数值列,MySQL将保存0。MySQL允许将特定的不正确日期值保存到DATE和DATETIME列(如“2000-02-31”或“2000-02-00”)。其观点在于,验证日期不是SQL服务器的任务。如果MySQL能保存日期值并准确检索相同的值,MySQL就能按给定的值保存它。如果日期完全不正确(超出服务器能保存的范围)将在列中保存特殊的日期值“0000-00-00”取而代之。如果试图将NULL值保存到不接受NULL值的列,对于单行INSERT语句,将出现错误。对于多行INSERT语句或INSERTINTO...SELECT语句,MySQL服务器会保存针对列数据类型的隐含默认值。一般情况下,对于数值类型,它是0,对于字符串类型,它是空字符串(‘‘),对于日期和时间类型是“zero”。如果INSERT语句未为列指定值,如果列定义包含明确的DEFAULT子句,MySQL将插入默认值。如果在定义中没有这类DEFAULT子句,MySQL会插入列数据类型的隐含默认值。采用前述规则的原因在于,在语句开始执行前,无法检查这些状况。如果在更新了数行后遇到这类问题,我们不能仅靠回滚解决,这是因为存储引擎可能不支持回滚。中止语句并不是良好的选择,在该情况下,更新完成了“一半”,这或许是最差的情况。对于本例,较好的方法是“仅可能做到最好”,然后就像什么都未发生那样继续。在MySQL5.0.2和更高版本中,可以使用STRICT_TRANS_TABLES或STRICT_ALL_TABLESSQL模式,选择更严格的处理方式。STRICT_TRANS_TABLES的工作方式:对于事务性存储引擎,在语句中任何地方出现的不良数据值均会导致放弃语句并执行回滚。对于非事务性存储引擎,如果错误出现在要插入或更新的第1行,将放弃语句。(在这种情况下,可以认为语句未改变表,就像事务表一样)。首行后出现的错误不会导致放弃语句。取而代之的是,将调整不良数据值,并给出告警,而不是错误。换句话讲,使用STRICT_TRANS_TABLES后,错误值会导致MySQL执行回滚 *** 作,如果可以,所有更新到此为止。要想执行更严格的检查,请启用STRICT_ALL_TABLES。除了非事务性存储引擎,它与STRICT_TRANS_TABLES等同,即使当不良数据出现在首行后的其他行,所产生的错误也会导致放弃语句。这意味着,如果错误出现在非事务性表多行插入或更新过程的中途,仅更新部分结果。前面的行将完成插入或更新,但错误出现点后面的行则不然。对于非事务性表,为了避免这种情况的发生,可使用单行语句,或者在能接受转换警告而不是错误的情况下使用STRICT_TRANS_TABLES。要想在第1场合防止问题的出现,不要使用MySQL来检查列的内容。最安全的方式(通常也较快)是,让应用程序负责,仅将有效值传递给数据库。有了严格的模式选项后,可使用INSERTIGNORE或UPDATEIGNORE而不是不带IGNORE的INSERT或UPDATE,将错误当作告警对待。
解决方法如下:
一、检查是否乱码。更改统一的字符类型,比如更改字符类型为utf8;
二、如果是 Enum,则可能是添加的字符不在enum类型范围内;
三、可能是在alter table更改列设置时,影响原来存入的值,这时可将原值update为需要的类型值或删除这些原值再alter table。
四、检查是不是数据类型的长度不一致导致的。这个比较麻烦具体步骤如下:
1、程序中检查日期的范围,当超出时给出提示或其他处理
2、找到mysql 安装目录的 my.ini
3、找到sql-mode=”STRICT_TRANS_TABLES,NO_AUTO_Create_USER,NO_ENGINE_SUBSTITUTION”把其中的 STRICT_TRANS_TABLES,去掉,然后重启mysql。
此外在写日期类型时也要注意,mysql 的date类型 的支持范围是1000-01-01到9999-12-31,datetime类型的支持范围是1000-01-01 00:00:00 到 9999-12-31 23:59:59。如果尝试把超出范围的值插入数据库中,则会报标题中的错误。采用datetime类型的时候,当日期超出范围时,插入数据库时不报错,但会是一个0000-00-00 或者0000-00-00 00:00:00
扩展资料:
MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,目前属于 Oracle 旗下产品。MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的 RDBMS (Relational Database Management System,关系数据库管理系统) 应用软件。
MySQL是一种关系数据库管理系统,关系数据库将数据保存在不同的表中,而不是将所有数据放在一个大仓库内,这样就增加了速度并提高了灵活性。
MySQL所使用的 SQL 语言是用于访问数据库的最常用标准化语言。MySQL 软件采用了双授权政策,分为社区版和商业版,由于其体积小、速度快、总体拥有成本低,尤其是开放源码这一特点,一般中小型网站的开发都选择 MySQL 作为网站数据库。
由于其社区版的性能卓越,搭配 PHP 和 Apache 可组成良好的开发环境。
参考资料:
MySQL官方API接口-Chapter 9 Language Structure
百度百科-MySQL
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)