sql server 导出的datetime结果 CAST(0x00009E0E0095524F AS DateTime) 如何向mysql,oracle等数据库进行转换

在进行sql server向mysql等其他数据进行迁移数据时,会发现使用sql server导出的datetime类型的结果是16进制表示的二进制的结果,类似于:CAST(0x00009E0E0095524F AS DateTime),这样形式的datetime是无法向其他数据库插入的,所以需要将这种表现形式进行转换。搜索了很久,才在在stackoverflow上找到正确的转换方法。在网上看到很多人都这个问题都不知道解决办法,本文采用Java语言根据stackoverflow介绍的原理,进行编码实现转换。

注意,因为datetime分为了4字节形式和8字节形式,所有对应的又两种转换方法。另外本转义方法,只能精确到秒级别,毫秒级别是不精确的。如果需要完全精确的转换,请采用其他工具进行转换,比如sqlyog, mysql workbench等工具。

下面是具体的代码:

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * sql server数据库在向mysql等数据库迁移数据时,会遇到一个麻烦,sql server导出的datetime的结果是16进制形式的二进制结果,
 * 类似于 CAST(0x00009E0E0095524F AS DateTime),这样的导出结果是无法直接向mysql数据库中导入的,所以需要对sql server
 * 导出的脚本中的所有的 datetime 字段类型进行转换,转换成mysql等数据库认可的结果:2010-10-13 09:03:39
 * 才能正确的完成sql server数据向mysql等数据库的迁移。
 * 注意本方法只能精确到秒级别,毫秒级别是不精确的。
 * 具体转换原理,参见:http://stackoverflow.com/questions/12033598/cast-hex-as-datatime-how-to-get-date
 * @author [email protected]
 */
public class SqlServerDateTimeToMysql {
    private static final Calendar cal = Calendar.getInstance();

    static{
        cal.set(Calendar.YEAR, 1900);
        cal.set(Calendar.MONTH, Calendar.JANUARY);
        cal.set(Calendar.DATE, 1);
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
    }

    /**
     * 将sql server导出的datetime字段结果 CAST(0x00009E0E0095524F AS DateTime),转换成
     * 2010-10-13 09:03:39 ,以利于 sql server 向 mysql, oracle 迁移数据
     * @param dateTimeStr
     * @return
     * reference: http://stackoverflow.com/questions/12033598/cast-hex-as-datatime-how-to-get-date
     */
    public static String convertSqlServerDateTimeToMySQLDateTime(String dateTimeStr){
        return convertToMySQLDateTime(dateTimeStr, false);
    }

    /**
     * 将sql server导出的datetime字段结果 CAST(0x00009E0E0095524F AS DateTime),转换成
     * 2010-10-13 09:03:39 或者 2010-10-13 09:03:39.394 注意毫秒部分不精确
     * @param dateTimeStr
     * @param millisecondFlag
     * @return
     * reference: http://stackoverflow.com/questions/12033598/cast-hex-as-datatime-how-to-get-date
     */
    public static String convertToMySQLDateTime(String dateTimeStr, boolean millisecondFlag) {
        if (dateTimeStr == null || dateTimeStr.trim().equals(""))
            return null;

        String rawData = dateTimeStr.substring("CAST(".length(), dateTimeStr.toUpperCase().indexOf(" AS DATETIME"));
        if (rawData == null || rawData.trim().equals(""))
            return null;

        rawData = rawData.trim();
        String result = null;

        if(rawData.length() <= 10){        // rowData = "0x993a02CE"
            result = getMySQLDateTime4Bytes(rawData);
        }
        if(rawData.length() > 10 && rawData.length() <= 18){    // rowData = "0x00009E0E0095524F"
            if(millisecondFlag)
                result = getMySQLDateTime8Bytes2(rawData);    // 返回值带毫秒,毫秒部分不精确
            else
                result = getMySQLDateTime8Bytes(rawData);    // 精确到秒,返回值不带毫秒
        }
        return result;
    }

    /**
     * sql server 利用 Small DateTime 4个字节
     * select CAST(0x993902CE as  SmallDateTime);
     * 2007-05-25 11:58:00 (只精确到分钟???)
     *
     * mysql:
     * SELECT "0x993902CE" INTO @raw_data;
     * SELECT conv(substr(@raw_data, 3, 4), 16, 10) INTO @days;
     * SELECT conv(substr(@raw_data, 7, 4), 16, 10) INTO @minutes;
     * SELECT "1900-01-01 00:00:00" INTO @start_date;
     * SELECT date_add(@start_date, interval @days DAY) INTO @date_plus_years;
     * SELECT date_add(@date_plus_years, interval @minutes MINUTE) INTO @final_date;
     * select @final_date;
      * 2007-05-25 11:58:00
     * @param rawData
     * @return
     */
    private static String getMySQLDateTime4Bytes(String rawData){
        String day = rawData.substring(2, 2 + 4);    // rowData = "0x993a02CE"
        String minutes = rawData.substring(6, 6 + 4);

        Calendar calendar =  Calendar.getInstance();
        calendar.setTimeInMillis(cal.getTimeInMillis());    // 1900-01-01 00:00:00

        calendar.add(Calendar.DATE, Integer.parseInt(day, 16));
        calendar.add(Calendar.MINUTE, Integer.parseInt(minutes, 16));

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        return sdf.format(calendar.getTime());
    }

    /**
     * sql server DateTime 利用 8 字节表示, 该转换精确到秒,无毫秒部分
     * @param rawData
     * @return mysqlDateTime
     *
     */
    private static String getMySQLDateTime8Bytes(String rawData){
        String day = rawData.substring(2, 2 + 8);
        String seconds = rawData.substring(10, 10 + 8);

        Calendar calendar =  Calendar.getInstance();
        calendar.setTimeInMillis(cal.getTimeInMillis());    // 1900-01-01 00:00:00

        calendar.add(Calendar.DATE, Integer.parseInt(day, 16));
        calendar.add(Calendar.SECOND, (int)(Integer.parseInt(seconds, 16)*3.33333/1000)); // 3.33333 后面的3越多越精确,带4位小数就行了

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");    

        return sdf.format(calendar.getTime());
    }

    /**
     * sql server DateTime 利用 8 字节表示 , 该转换精确到秒,有毫秒部分
     * @param rawData
     * @return mysqlDateTime
     */
    private static String getMySQLDateTime8Bytes2(String rawData){
        String day = rawData.substring(2, 2 + 8);
        String seconds = rawData.substring(10, 10 + 8);

        Calendar calendar =  Calendar.getInstance();
        calendar.setTimeInMillis(cal.getTimeInMillis());    // 1900-01-01 00:00:00

        calendar.add(Calendar.DATE, Integer.parseInt(day, 16));
//        BigDecimal decimal = new BigDecimal("3.3333333333");    // 使用BigDecimal在精度方面似乎没有什么作用
//        decimal = decimal.multiply(new BigDecimal(Integer.parseInt(seconds, 16)));
//        decimal = decimal.divide(new BigDecimal("1000"));
//        calendar.add(Calendar.MILLISECOND, (int)(Integer.parseInt(seconds, 16)*3.33333));//        calendar.add(Calendar.MILLISECOND, decimal.intValue());
//        calendar.add(Calendar.SECOND, decimal.intValue());    // 使用 Calendar.MILLISECOND 来处理,反而会导致秒级别的误差!不知道为什么

        calendar.add(Calendar.SECOND,  (int)(Integer.parseInt(seconds, 16)*3.33333/1000));
//      calendar.add(Calendar.MILLISECOND,  (int)(Integer.parseInt(seconds, 16)*3.33333)); // Calendar.MILLISECOND 会导致秒级别的误差
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");    // 毫秒部分是不精确的,每次运行的结果不相同!    

        return sdf.format(calendar.getTime());
    }

    public static void main(String[] args) {

        // select CAST(0x00009E0E0095524F AS DateTime) == 2010-10-13 09:03:39.783  正确的日期值
        String str = "CAST(0x00009E0E0095524F AS DateTime)";
        System.out.println(convertToMySQLDateTime(str, true));    // 2010-10-13 09:03:39.374 毫秒部分不精确
        System.out.println(convertSqlServerDateTimeToMySQLDateTime(str));    // 2010-10-13 09:03:39 秒级别是精确的

        try {
            // 这里的字符集一般是 StandardCharsets.UTF_16 或者 StandardCharsets.UTF_8,具体看你导出时采用的是哪种字符集
            BufferedReader reader = Files.newBufferedReader(Paths.get("F:\\Members.sql"), StandardCharsets.UTF_16);
            BufferedWriter writer = Files.newBufferedWriter(Paths.get("F:\\Members_mysql.sql"), StandardCharsets.UTF_16);

            String line = null;
            Matcher matcher = null;
            String matcherStr = null;
            String reg = ".*((?i)CAST\\(0x[0-9-a-f-A-F]+ AS DateTime\\)).*"; // ( 为特殊字符,表示普通的( 需要用 \\( 来转义表示
            Pattern pattern = Pattern.compile(reg);

            while ((line = reader.readLine()) != null) {
                while (line.matches(reg)) {
                    matcher = pattern.matcher(line);
                    matcherStr = null;
                    if (matcher.find()) {
                        matcherStr = matcher.group(1);    // matcherStr = "CAST(0x00009E0E0095524F AS DateTime)"
                        if (matcherStr != null) {
                            String mysqlStr = convertSqlServerDateTimeToMySQLDateTime(matcherStr);
                            if(mysqlStr != null)
                                line = line.replace(matcherStr, " " + mysqlStr + " "); // mysqlStr = 2010-10-13 09:03:39
                        }
                    } else {
                        break;    // break inner while loop
                    }
                }
                writer.write(line);
                writer.newLine();
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println("done.");
    }

}

正则表达式 String reg = ".*((?i)CAST\\(0x[0-9-a-f-A-F]+ AS DateTime\\)).*"; 其中的 (?i) 表示不区分字符的大小写,类似于js中的 /xx/i

在 F:\\Members.sql 中保存的是sql server导出的insert语句形式的数据:

INSERT [Members] ([g_MemberID], [FK_GroupId], [FK_UserId], [FK_C_UserId], [g_Member_State], [g_Member_Jobtitle], [g_Member_Open], [g_Member_Nickname], [g_Member_FirstnamePY], [g_Member_Firstname], [g_Member_LastnamePY], [g_Member_Lastname], [g_Member_sex], [g_Member_Birthday], [g_Member_MaritalStatus], [FK_City], [g_Member_FacePath], [g_Member_Address], [g_Member_Mobile], [g_Member_hometel], [g_Member_Email], [g_Member_QQ], [g_Member_Wangwang], [g_Member_Msn], [g_Member_Note], [g_Member_JoinTime], [FK_User_AttnUserID], [g_push], [g_Member_Order], [gmt_last_modified]) VALUES (1, 1, 4, 4, 40, NULL, 30, N‘大手机‘, N‘‘, N‘‘, N‘总‘, N‘总‘, N‘M‘, N‘2013-11-31‘, NULL, 11, N‘20131231/2013123115MF0DD3.jpg‘, N‘‘, N‘13900000000‘, N‘‘, N‘‘, N‘‘, N‘‘, N‘‘, N‘‘, NULL, NULL, NULL, NULL, CAST(0x0000A2A500FC2E4F AS DateTime))
INSERT [Members] ([g_MemberID], [FK_GroupId], [FK_UserId], [FK_C_UserId], [g_Member_State], [g_Member_Jobtitle], [g_Member_Open], [g_Member_Nickname], [g_Member_FirstnamePY], [g_Member_Firstname], [g_Member_LastnamePY], [g_Member_Lastname], [g_Member_sex], [g_Member_Birthday], [g_Member_MaritalStatus], [FK_City], [g_Member_FacePath], [g_Member_Address], [g_Member_Mobile], [g_Member_hometel], [g_Member_Email], [g_Member_QQ], [g_Member_Wangwang], [g_Member_Msn], [g_Member_Note], [g_Member_JoinTime], [FK_User_AttnUserID], [g_push], [g_Member_Order], [gmt_last_modified]) VALUES (2, 2, 4, 4, 40, N‘锦鲤‘, 30, N‘‘, N‘‘, N‘测试‘, N‘总‘, N‘陈‘, N‘M‘, N‘2013-11-31‘, 0, 11, N‘20140324/2014032409Xva2Ix.jpg‘, N‘‘, N‘13900000000‘, N‘‘, N‘‘, N‘‘, N‘‘, N‘‘, N‘‘, NULL, NULL, NULL, NULL, CAST(0x0000A2F80095DF52 AS DateTime))

转换之后的结果保存在 F:\\Members_mysql.sql 中,类似于:

INSERT [Members] ([g_MemberID], [FK_GroupId], [FK_UserId], [FK_C_UserId], [g_Member_State], [g_Member_Jobtitle], [g_Member_Open], [g_Member_Nickname], [g_Member_FirstnamePY], [g_Member_Firstname], [g_Member_LastnamePY], [g_Member_Lastname], [g_Member_sex], [g_Member_Birthday], [g_Member_MaritalStatus], [FK_City], [g_Member_FacePath], [g_Member_Address], [g_Member_Mobile], [g_Member_hometel], [g_Member_Email], [g_Member_QQ], [g_Member_Wangwang], [g_Member_Msn], [g_Member_Note], [g_Member_JoinTime], [FK_User_AttnUserID], [g_push], [g_Member_Order], [gmt_last_modified]) VALUES (1, 1, 4, 4, 40, NULL, 30, N‘大手机‘, N‘‘, N‘‘, N‘总‘, N‘总‘, N‘M‘, N‘2013-11-31‘, NULL, 11, N‘20131231/2013123115MF0DD3.jpg‘, N‘‘, N‘13900000000‘, N‘‘, N‘‘, N‘‘, N‘‘, N‘‘, N‘‘, NULL, NULL, NULL, NULL,  2013-12-31 15:18:09 )
INSERT [Members] ([g_MemberID], [FK_GroupId], [FK_UserId], [FK_C_UserId], [g_Member_State], [g_Member_Jobtitle], [g_Member_Open], [g_Member_Nickname], [g_Member_FirstnamePY], [g_Member_Firstname], [g_Member_LastnamePY], [g_Member_Lastname], [g_Member_sex], [g_Member_Birthday], [g_Member_MaritalStatus], [FK_City], [g_Member_FacePath], [g_Member_Address], [g_Member_Mobile], [g_Member_hometel], [g_Member_Email], [g_Member_QQ], [g_Member_Wangwang], [g_Member_Msn], [g_Member_Note], [g_Member_JoinTime], [FK_User_AttnUserID], [g_push], [g_Member_Order], [gmt_last_modified]) VALUES (2, 2, 4, 4, 40, N‘锦鲤‘, 30, N‘‘, N‘‘, N‘测试‘, N‘总‘, N‘陈‘, N‘M‘, N‘2013-11-31‘, 0, 11, N‘20140324/2014032409Xva2Ix.jpg‘, N‘‘, N‘13900000000‘, N‘‘, N‘‘, N‘‘, N‘‘, N‘‘, N‘‘, NULL, NULL, NULL, NULL,  2014-03-24 09:05:40.358 )

可以看到

CAST(0x0000A2A500FC2E4F AS DateTime) 被转换成了:2013-12-31 15:18:09

CAST(0x0000A2F80095DF52 AS DateTime) 被转换成了:2014-03-24 09:05:40

当然要达到直接运行插入mysql数据中,还要去的 [g_MemberID] 中的 [] 中括号(这几采用替换的方式就行了),还有每一行的末尾要加上逗号 , 再者 INSERT [Members] ([g_MemberID], [FK_GroupId], ...) 语句只需要出现一次,采用 insert into tab(col_a,col_b,col_c) values (1,2,3), values(4,5,6) ... 这样的插入形式,可以明显提高插入速度。

另外,如果sql server导出时,如果选择导出到excel时,datetime字段的值是不需要进行转换的。在数据量很小时,可以选中这种方式。

时间: 2024-08-24 23:44:59

sql server 导出的datetime结果 CAST(0x00009E0E0095524F AS DateTime) 如何向mysql,oracle等数据库进行转换的相关文章

用SQL server导出到oracle,查询时提示“表或视图不存在ORA-00942”错误

用SQL server2005的导出工具,将数据导出表到oracle,表名称里看到有这张表了,但查询或删除时都提示“ORA-00942表或者试图不存在”的错误,上网查了一下,是如下原因: “查询或删除名称存在的表时,却提示不存在,你看看在user_tables里这几个表名是小写吗? 那说明你建表的时候肯定带引号了,请select的时候也带上引号.例如:select * from "tableName",可以看出如果在SQLserver中,如果表名是小写的,那导入到oracle时,建表时

远程将sql server导出成 mysql

远程将sql server导出成 mysql 我使用的是Navicat for Mysql 工具: 步骤一: 现在mysql建好库 XXXXX, 步骤二: 出现下面界面: 这里需要填 sql server服务器的地址和 数据库的帐号密码登录成功 3.才会出现 数据库中库的列表,然后选择你需要导出的库: 下一步: 确定之后得到上面这张,全选你懂得:根据提示 下一步: 最后执行下 开始就OK,有需要也可以保存为.sql文件备份.

SQL Server 检测到基于一致性的逻辑 I/O 错误 pageid不正确、数据库日志文 件丢失

客户名称:深圳某科技信息有限公司 数据库类型:sql2000 数据库大小:20g 故障经过 电脑突然断电,软件就显示某数据库错误,无法连接,打开企业管理器,显示数 据库质疑,DBCC查询显示" SQL Server 检测到基于一致性的逻辑 I/O 错误 pageid不正确.数据库日志文件丢失". 处理经过 客户找到我们,然后我们让客户把数据库压缩发给我们,首先我们先对数据进行 检测分析,确定是" I/O 错误 ",然后我们就开始用我们的修复工具对数据进 行全面性的分

关于SQL SERVER导出数据的问题!

前面一段时间,为这个导出数据真是煞费苦心,网上找了好多资料都没有找到. 从SQL SERVER 2008开始,我们就可以很方便的导出数据脚本,而无需再借助存储过程,但是SQL Server 2012和SQL Server 2008的导出脚本的过程还有一点细微的差别,我在这里详细的介绍一下. 在SQL Server 2012中我们无法直接找到例如下图中的编写数据的脚本的选项. 由于是SQL 版本问题,所以建立的数据库不能附加,需要生成脚本,才另个sql上进行创建.so

SQL server 导出平面文件时出错: The code page on Destination - 3_txt.Inputs[Flat File Destination Input].Columns[UserId] is 936 and is required to be 1252.

我在导出平面文件时:Error 0xc00470d4: Data Flow Task 1: The code page on Destination - 3_txt.Inputs[Flat File Destination Input].Columns[UserId] is 936 and is required to be 1252.(SQL Server Import and Export Wizard)有时可以验证通过,有时不可以,这是啥原因? 我试过使用Unicode编码方式(有时可以)

sql server 导出数据到 Azure Hbase / Hive 详细步骤

The Hadoop on Azure Sqoop Import Sample Tutorial Table of Contents Overview Goals Key technologies Setup and Configuration Tutorial How to set up a SQL database How to use Sqoop from Hadoop on Azure to import SQL Database query results to the HDFS cl

sql server导出insert语句

在所需要导出数据库上右键 选择[任务] 然后选择[生成脚本] 选择数据库,点击下一步到[数据脚本选项] 编写数据的脚本 选择为true  这一步很重要 下一步选择要导出的对象 下一步选择表 点击完成 等待数据库相应 ok

Sql Server 导出数据库表结构的SQL查询语句

1 --导出数据库所有表 2 3 SELECT 4 表名 = Case When A.colorder=1 Then D.name Else '' End, 5 表说明 = Case When A.colorder=1 Then isnull(F.value,'') Else '' End, 6 字段序号 = A.colorder, 7 字段名 = A.name, 8 字段说明 = isnull(G.[value],''), 9 标识 = Case When COLUMNPROPERTY( A.

SQL Server 2008 R2——VC++ ADO 操作 存储过程 向datetime类型参数传入空值

==================================声明================================== 本文原创,转载在正文中显要的注明作者和出处,并保证文章的完整性. 未经作者同意请勿修改(包括本声明),保留法律追究的权利. 未经作者同意请勿用于出版.印刷或学术引用. 本文不定期修正完善,为保证内容正确,建议移步原文处阅读. 本文链接:http://www.cnblogs.com/wlsandwho/p/4382897.html =============