由SQLServer的数据导出时间转化问题引发的
问题描述
使⽤SQL Server 2012 附加⼀个数据库之后,想批修改数据中的时间,把时间⽇期提前,因为有很多表中有时间字段,在⼀个个表,⽤sql更新,过于枯燥。想⼀个⼀次性把所有表时时间都换成⼀样的⽅式。所以想到导出成sql脚本,然后⽤正则表达式查替换,再重新建库。(当然情况是表⽐较多,但每个表中的数据量并不太多)
过程
先是参考
发现只导出了表结构,未导出数据。
再到了这篇 才搞定。
评价⼏句
没有记住上次向导的配置,每次导都要再配置⼀次,不⽅便。
⾼级配置⾥的选项那多么,却只分配那么⼩的框,要上下移,都做成向导页⾯了,就放⼀个⾼级配置的向导页就OK了嘛。
默认配置不合理。
新问题
数据是导出来了。
但发现插⼊时间的语句是这样的INSERT [dbo].[test] ([dt]) VALUES (CAST(0x0000A44E00000000 AS DateTime))。
那CAST后⾯的长串16进制是什么⿁。
碰见反常的东西,是要好奇查查。
MSDN ⾥ ,按图索冀 然后就呵呵,断了。
查msdn时,总有这样的感觉,A页⾯说,详细请见B页⾯,然后B页⾯就是与A页⾯没太⼤联系的说明。
为什么要设计成这样,⾮要再转⼀次才能看到真的时间?
继续摸
如果时间紧,就不⽤在这⾥再探索那16个字符与时间的对应关系了。建个临时表,再导出需要调整的时间,再⽤导出的那个16进制数,替换那所有的数据就可以了。重放攻击的原理?
我想了解那个与时间的对应关系,先google了⼏把,为好选关键字,没到。
于是我就⾃定义的⼀些数据,再导出来。⽐较数据,来看看到底是什么关系。
这是建表语句:
create table test(dt datetime);
insert into test values('2015-03-01');
insert into test values('2015-03-02');
insert into test values('2015-03-03');
insert into test values('2015-03-04 12:00:00.000');
insert into test values('2015-03-04 12:00:00.001');
insert into test values('2015-03-04 12:00:01.000');
insert into test values('2015-03-04 12:01:00.000');
insert into test values('2015-03-04 13:01:00.000');
导出的数据为:
INSERT [dbo].[test] ([dt]) VALUES (CAST(0x0000A44E00000000AS DateTime))
INSERT [dbo].[test] ([dt]) VALUES (CAST(0x0000A44F00000000AS DateTime))
INSERT [dbo].[test] ([dt]) VALUES (CAST(0x0000A45000000000AS DateTime))
INSERT [dbo].[test] ([dt]) VALUES (CAST(0x0000A45100000000AS DateTime))
INSERT [dbo].[test] ([dt]) VALUES (CAST(0x0000A45100C5C100AS DateTime))
INSERT [dbo].[test] ([dt]) VALUES (CAST(0x0000A45100C5C100AS DateTime))
时间正则表达式java
INSERT [dbo].[test] ([dt]) VALUES (CAST(0x0000A45100C5C22C AS DateTime))
INSERT [dbo].[test] ([dt]) VALUES (CAST(0x0000A45100C60750AS DateTime))
INSERT [dbo].[test] ([dt]) VALUES (CAST(0x0000A45100D68210AS DateTime))
规律:
⽇期加1时,前四个字节的数据就加1。猜想不会不是⼀个天数呢,先把前四个字节转成10进制42062,再除以365,再减现在的年
份,1900?,验算下,从1900-01-01到2015-03-01的确是42062天。
unix时间戳是1970年开算,嘿嘿,它就⾮要不⼀样。
想看看1900与时间戳有什么关系。google⼀把,终于到了⼀篇帖⼦
Microsoft SQL Server ⽤两个 4 字节的整数内部存储 datetime 数据类型的值。第⼀个 4 字节存储 base date(即 1900 年 1 ⽉
1 ⽇)之前或之后的天数。基础⽇期是系统参考⽇期。不允许早于 1753 年 1 ⽉ 1 ⽇的 datetime 值。
另外⼀个 4 字节存储以午夜
后毫秒数所代表的每天的时间。
smalldatetime 数据类型存储⽇期和每天的时间,但精确度低于 datetime。SQL Server 将 smalldatetime 的值存储为两个 2 字节的整数。第⼀个 2 字节存储 1900 年 1 ⽉ 1 ⽇后的天数。另外⼀个 2 字节存储午夜后的分钟数。⽇期范围从1900 年 1 ⽉ 1 ⽇到2079 年 6 ⽉ 6 ⽇,精确到分钟。
到这⾥,问题算是解决了。
结果
这样⼀个“奇怪”的写法,是可能是为解决两个问题:
精度问题,要精确到毫秒,⼜要时间跨度。
时间区问题,显⽰的写时间,未指定时区,在不同时区执⾏会引发问题。
但还有三点问题
第四⾏和第五⾏,插⼊时,相差1ms,但导出时,数据是⼀样的?
现是东⼋区,取后四字节算出来的12点的时间是到3点的。奇怪?
如果是1900之前的时间,会出现什么情况呢?
等有空时再试试。
总结&反思
这样⼀个问题的确也折腾了我不少时间。是否值得?(本来可能不值的,但写了这篇总结后,是值得的)
问题的⽅式和⽅向是不是错了?在试着CAST等关键字不⾏时,为什么没有“回溯”换成查这个数据类型相关资料,⽽要⾃⼰蛮⼒的规律?这是程序员的⼀分负⾯的执着。
⼀些看起来奇怪的事,可能是⾃⼰知识有限,未考虑到的情况,应抱着谦虚的⼼态,搞明⽩为什么,多交流。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。