SQL SERVER的表结构及索引转换为MySQL的表结构及索引,其实在很多第三方工具中有提供,比如navicat、sqlyog等,但是,在处理某些数据类型、默认值及索引转换的时候,总有些不尽人意并且需要安装软件,懒人开始想法子,所以基于SQL SERVER,写了一个存储过程,可以根据表名直接转换为MySQL的建表建索引的SQL脚本(针对 MySQL Innodb引擎)。目前不支持分区表的分区配置及区域数据类型的转换。
 


 
    如果转载,请注明博文来源: www.cnblogs.com/xinysu/   ,版权归 博客园 苏家小萝卜 所有。望各位支持!
 


    建表的SQL中,主要在数据类型转换、主键及索引的处理。

1 数据类型转换

    数据类型转换表详见下表,这些数据类型的转换目前已测试过,均可正常使用。
    但是注意两类数据库存储数据的一些差异,看下能否接受:
  • SQL SERVER中的datetime,保留到微秒(秒后小数点3位),而mysql仅保留到秒,转换后是否会影响业务,如果影响,需要新增一个字段专门来存储微秒或者毫秒,虽然mysql中没有时间数据类型的精度到达微秒或者毫秒,但是mysql提供对微秒的相关处理函数microsecond、extract跟date_format。
  • MySQL使用tinyint代替SQL SERVER的bit
  • SQL SERVER的money类型使用decimal替代
  • timestamp的转换,SQL SERVER中是一个16进制的数字,代表时间戳,每次修改都会数值都会变大。
    • 从功能考虑,转换为mysql的时候,处理为timestamp的数据类型,默认值为CURRENT_TIMESTAMP,行发生修改则定时修改这一列数据,如果这样转换,那么在SQL SERVER导入数据的时候,就要相应处理。(本文存储过程默认这么处理)
    • 从数据考虑,转换为mysql的时候,处理为bigint的数据类型(修改存储过程case when b.name = 'timestamp' then ' timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ' 为case when b.name = 'timestamp' then ' bigint ' )
  • 自增处理,mysql的自增步长跟增量值是整个实例统一的,不能每个表格动态修改,所以这里在转化的过程中,为auto_increment,根据实例的设置来处理
 
ID SQL SERVER MySQL Description
1 bigint bigint  
2 binary binary  
3 bit tinyint SQL SERVER的bit类型,对于零,识别为False,非零值识别为True。
MySQL中没有指定的bool类型,一般都使用tinyint来代替
4 char char  
5 date date  
6 datetime datetime 注意,mssql的保留到微秒(秒后小数点3位),而mysql仅保留到秒
7 datetime2 datetime 注意,mssql的保留到微秒(秒后小数点7位),而mysql仅保留到秒
8 datetimeoffset datetime 注意,mssql的保留时区,这个需要程序自己转换
mssql的保留到微秒(秒后小数点7位),而mysql仅保留到秒
9 decimal decimal  
10 float float  
11 int int  
12 money float 默认转换为decimal(19,4)
13 nchar char SQL SERVER转MySQL按正常字节数转就可以
14 ntext text  
15 numeric decimal  
16 nvarchar varchar  
17 real float  
18 smalldatetime datetime  
19 smallint smallint  
20 smallmoney float 默认转换为decimal(10,4)
21 text text  
22 time time 注意,mssql的保留到秒后小数点8位,而mysql仅保留到秒
23 timestamp timestamp 注意,mssql的行时间戳,处理为mysql的 timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP 。这会对后面导数据造成影响,从功能方面来看,可以按照上文转换;如果从数据来看,若需要转换16进制的文字存储到mysql中,则这里设置为bigint即可,在表格中的临时表中设置。
24 tinyint tinyint  
25 uniqueidentifier varchar(40) 对应mysql的UUID(),设置为文本类型即可。
26 varbinary varbinary  
27 varchar varchar  
28 xml text mysql不支持xml,修改为text
 

2 主键处理

    MySQL不支持非主键的聚集索引,也就是聚集索引则是主键。故在转换的过程中,主键是根据SQL SERVER表格中的聚集索引来转换的。
 
  1. --SQL SERVER根据聚集索引的列情况来创建mysql的主键
  2. SELECT
  3. col_name(i.object_id,ik.column_id) pk_col
  4. FROM sys.indexes i
  5. JOIN sys.index_columns ik ON i.index_id=ik.index_id and i.object_id=ik.object_id
  6. WHERE i.type=1
  7. and i.object_id=object_id('tb')
  8. ORDER BY key_ordinal

3 索引添加

    由于聚集索引已处理添加为主键,在建表的SQL中已判断,这里则只处理非聚集索引。
    处理过程中注意:
  • MySQL不支持INCLUDE选项的包含索引,所以在处理的过程中,INCLUDE列添加到索引列中
  • MySQL 不支持WHERE选项的过滤索引,所以在处理的过程中,WHERE选项去除
  • 索引名字处理:包含列1-2个的,直接IX_表名,超过3个列的,取每列前3个字符,整个索引名长度不超过64个字符,超过截取前64个字符

4 测试

    存储过程 [p_tb_mssqltomysql] 仅含一个参数 @tbsql,用于存储表格名字,多个表格名中间有逗号隔开,不要有空格或者其他符号。
   

这里,尝试创建一个新表来测试。

    创建表格及对应索引信息测试如下:
  1. CREATE TABLE tbtest(
  2. id INT IDENTITY(1,1) NOT NULL ,
  3. name NVARCHAR(50) NOT NULL,
  4. phone VARCHAR(11) NOT NULL,
  5. age int default 99 ,
  6. birthday datetime default getdate(),
  7. addresss text,
  8. monyes money default 123456789012345.1234,
  9. smonyes smallmoney,
  10. nums int default 2,
  11. moneys money,
  12. smo smallmoney,
  13. curversion timestamp
  14. )
  15.  
  16. ALTER TABLE tbtest ADD CONSTRAINT PK_tbtest PRIMARY KEY (ID,phone);
  17. CREATE INDEX IX_NAME ON tbtest(NAME);
  18. CREATE INDEX IX_phone_age ON tbtest(phone,age);
  19. CREATE INDEX IX_nums ON tbtest(nums) WHERE nums>2;
  20. CREATE INDEX IX_birthday ON tbtest(birthday) include (name,phone);
 
    执行存储过程转化:
 
  1. exec p_tb_mssqltomysql 'tbtest'
  2.  
  3. CREATE TABLE tbtest(id int not null auto_increment
  4. ,name varchar(50) not null
  5. ,phone varchar(11) not null
  6. ,age int null
  7. ,birthday datetime null
  8. ,addresss text null
  9. ,monyes decimal(19,4) null
  10. ,smonyes decimal(10,4) null
  11. ,nums int null
  12. ,moneys decimal(19,4) null
  13. ,smo decimal(10,4) null
  14. ,curversion timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP not null
  15. , primary key (id,phone) );
  16. CREATE INDEX IX_name ON tbtest( name );
  17. CREATE INDEX IX_phone_age ON tbtest( phone,age );
  18. CREATE INDEX IX_nums ON tbtest( nums );
  19. CREATE INDEX IX_bir_nam_pho ON tbtest( birthday,name,phone );
 
    在mysql中创建正常,查看mysql的建表脚本如下:
 
 

5 存储过程脚本

    SQL SERVER转换MySQL表结构及索引的脚本如下:
 
  1. -- =============================================
  2. -- Author: suxinyu
  3. -- Create date: 20170612
  4. -- Description: 根据表名自动把表格的所有建表DDL SQL转化为 MySQL的建表SQL,不包含分区表,不处理区域数据类型;执行过程中,需要把存储过程建立在需要导出的数据库中。
  5. -- Example: exec p_tb_mssqltomysql 'orders,ordernums,channels'
  6. -- =============================================
  7. --存储过程建立在需要导出表结构的DB
  8.  
  9. USE db
    GO
  10.  
  11. CREATE PROC [dbo].[p_tb_mssqltomysql]
  12. @tbsql varchar(1000)
  13. AS
  14. SET NOCOUNT ON ;
  15.  
  16. --处理tablename的字符串,把tablename字符串分割成每一行存储进入表变量中
  17. DECLARE @tab_tablename table(tbname varchar(100))
  18. DECLARE @tbname varchar(100)
  19. INSERT INTO @tab_tablename(tbname)
  20. SELECT
  21.  
  22. SUBSTRING(@tbsql,NUMBER,CHARINDEX(',',@tbsql+',',NUMBER)-number)
  23. FROM master.dbo.spt_values
  24. WHERE TYPE='P' AND number>0 AND SUBSTRING(','+@tbsql,number,1)=','
  25.  
  26. --把mysqlmssql的数据类型对应起来存储
  27. --空间数据类型不处理
  28. --money类型处理为float
  29. --timestamp处理为 timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
  30. DECLARE @tbtype table(mssql varchar(20),mysql varchar(20))
  31. INSERT INTO @tbtype(mssql,mysql) values( 'bigint','bigint'),('binary','binary'),('binary','binary'),('bit','tinyint'),('char','char'),('date','date'),('datetime','datetime'),('datetime2','datetime'),('datetimeoffset','datetime'),('decimal','decimal'),('float','float'),('int','int'),('money','decimal'),('nchar','char'),('ntext','text'),('numeric','decimal'),('nvarchar','varchar'),('real','float'),('smalldatetime','datetime'),('smallint','smallint'),('smallmoney','decimal'),('text','text'),('time','time'),('timestamp','timestamp'),('tinyint','tinyint'),('uniqueidentifier','varchar(40)'),('varbinary','varbinary'),('varchar','varchar'),('xml','text')
  32.  
  33. DECLARE @tb_exec_sql table(tbname varchar(100),sql nvarchar(max),indexs nvarchar(max))
  34. DECLARE @indexs_sql nvarchar(max)
  35.  
  36. --转化表格SQL
  37. DECLARE NAME CURSOR FOR
  38.  
  39. SELECT tbname FROM @tab_tablename
  40. OPEN NAME
  41. FETCH NEXT FROM name INTO @tbname
  42. WHILE @@FETCH_STATUS =0
  43. BEGIN
  44. ;WITH data AS (
  45. SELECT
  46. case when b.is_unique=1 then ' UNIQUE ' else ' ' end is_unique,
  47. OBJECT_NAME(A.OBJECT_ID) obj_name,
  48. COL_NAME(A.object_id,A.column_id) colname,
  49. SUBSTRING(COL_NAME(A.object_id,A.column_id),1,3) col_short,
  50. is_included_column,
  51. index_column_id,
  52. a.index_id,
  53. A.OBJECT_ID
  54. FROM SYS.index_columns A INNER JOIN SYS.INDEXES B ON A.OBJECT_ID=B.OBJECT_ID AND A.index_id=B.index_id
  55. WHERE b.type!=1 and OBJECT_NAME(A.OBJECT_ID)=@tbname
  56. )
  57. SELECT
  58. @indexs_sql=
  59. REPLACE(
  60. (STUFF(
  61. (
  62. SELECT
  63. ' CREATE '
  64. + a.is_unique
  65. +' INDEX '
  66. + CASE WHEN COUNT(*) >=3 THEN SUBSTRING(('IX_'+stuff((SELECT '_'+col_short FROM data b where a.object_id=b.object_id and a.index_id=b.index_id FOR XML PATH('')),1,1,'')),1,64)
  67. ELSE 'IX_'+stuff((SELECT '_'+colname FROM data b where a.object_id=b.object_id and a.index_id=b.index_id FOR XML PATH('')),1,1,'')
  68. END
  69. +' ON '
  70. + a.obj_name
  71. +'( '
  72. + stuff((SELECT ','+colname FROM data b where a.object_id=b.object_id and a.index_id=b.index_id FOR XML PATH('')),1,1,'')
  73. +' );
  74. '
  75. FROM data a
  76. GROUP BY a.is_unique,a.obj_name,a.object_id,a.index_id
  77. ORDER BY a.object_id,a.index_id
  78. FOR XML PATH('')
  79.  
  80. ),1,1,'')
  81. ),'
  82. ','')
  83.  
  84. INSERT INTO @tb_exec_sql(tbname,indexs,sql)
  85. SELECT
  86. @tbname,@indexs_sql,
  87. 'CREATE TABLE '+@tbname+'('+
  88. REPLACE(
  89. STUFF( (
  90. SELECT
  91. ','+a.name
  92. +
  93. case when b.name = 'timestamp' then ' timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP '
  94. when b.name = 'uniqueidentifier' then ' varchar(40) '
  95. when b.name in ('char','nchar','nvarchar','varbinary','varchar') then ( case when a.length<0 then ' text ' else ' '+c.mysql+'('+ (case when b.name like 'n%' then cast(a.length/2 as varchar(10)) else cast(a.length as varchar(10)) end )+')' end )
  96. when b.name in ('decimal','float','money','numeric','smallmoney') then ' '+c.mysql+'('+ cast(a.prec as varchar(10)) +','+ cast(a.scale as varchar(10)) +') '
  97. else ' '+c.mysql+' ' end
  98. +
  99. case when a.isnullable=0 then ' not null ' else ' null ' end
  100. +
  101. case when COLUMNPROPERTY( A.ID,A.NAME,'ISIDENTITY')=1 then ' auto_increment ' else '' end
  102. +
  103. case when a.length<0 or b.name in ('text') then ' '
  104. when e.text like ' ((%' then ' default '+substring(e.text,3,len(e.text)-4)
  105. when e.text like ' (''%' then ' default '+substring(e.text,2,len(e.text)-2)
  106. else ' '
  107. end
  108. +
  109. ISNULL(' comment "'+cast(g.value as varchar(1000))+'"
  110. ','
  111. ')
  112.  
  113. FROM sys.syscolumns A
  114. LEFT JOIN sys.systypes B ON A.XUSERTYPE=B.XUSERTYPE
  115. LEFT JOIN @tbtype C ON b.name collate Chinese_PRC_CI_AS = c.mssql
  116. LEFT JOIN sys.sysobjects D ON A.ID=D.ID AND D.XTYPE='U' AND D.NAME<>'DTPROPERTIES'
  117. LEFT JOIN sys.syscomments E ON A.CDEFAULT=E.ID
  118. LEFT JOIN sys.extended_properties G ON A.ID=G.major_id AND A.COLID=G.minor_id
  119. WHERE D.NAME =@tbname
  120. order by a.colid
  121. FOR XML PATH('')
  122. ),1,1,'')
  123. ,'
  124. ','')
  125. +
  126. ISNULL(
  127.  
  128. ( SELECT
  129.  
  130. ', primary key ('+STUFF(
  131. (
  132. SELECT
  133.  
  134. ','+col_name(i.object_id,ik.column_id)
  135. FROM sys.indexes i
  136. JOIN sys.index_columns ik ON i.index_id=ik.index_id and i.object_id=ik.object_id
  137. WHERE i.type=1 and i.object_id=object_id(@tbname)
  138. ORDER BY key_ordinal
  139. FOR XML PATH('')
  140. ),1,1,'')
  141.  
  142. +') '
  143. )
  144. ,'')
  145. +
  146. ')'
  147. +
  148. ISNULL( (
  149. SELECT
  150. ' COMMENT "'+CAST(value AS VARCHAR(1000))+'";
  151. '
  152.  
  153. FROM sys.extended_properties
  154.  
  155. where major_id=object_id(@tbname) and minor_id=0
  156. ),';')
  157.  
  158. FETCH NEXT FROM NAME INTO @tbname
  159. END
  160. CLOSE NAME
  161. DEALLOCATE NAME
  162.  
  163. SELECT * FROM @tb_exec_sql

SQL SERVER 自动生成 MySQL 表结构及索引 的建表SQL的更多相关文章

  1. Entity Framewrok 7beta7中不同版本sql server自动生成分页sql语句的问题

    在EF中,使用linq进行分页是很方便的,假如我们有一个EMP表,结构如下: public class Emp { [Key] public Guid No { get; set; } public ...

  2. 【SQL】用Sql Server自动生产html格式的数据字典

    原文:[SQL]用Sql Server自动生产html格式的数据字典 本文软件环境:Sql Server 2008. 1.打开sql server管理器,给选定的表添加描述信息,给指定的字段添加描述信 ...

  3. SQL Server 动态生成数据库所有表Insert语句

    一. 背景 SQL Server,如果我们需要把数据库A的所有表数据到数据库B中,通常我们会怎么做呢?我会使用SSMS的导入导出功能,进行表数据的导入导出,无可厚非,这样的导入非常简单和方便: 但是, ...

  4. (转)如何将数据库从SQL Server迁移到MySQL

    一.迁移Database Schema. 首 先使用Sybase Powerdesigner的逆向工程功能,逆向出SQL Server数据库的物理模型.具体操作是在Powerdesigner中选择“F ...

  5. [PowerDesign]将数据库从SQL Server数据库转换为MySQL

    原文:[PowerDesign]将数据库从SQL Server数据库转换为MySQL 一.迁移Database Schema. 首先使用Sybase Powerdesigner的逆向工程功能,逆向出S ...

  6. 如何在SQL Server中生成和使用CRUD存储过程

    在本文中,请参阅如何在SQL Server中生成和使用CRUD存储过程. 大多数数据库系统基于缩写CRUD调用的最简单的4种数据操作操作进行操作. 此首字母缩写词代表CREATE,READ,UPDAT ...

  7. 通过SQL Server 2008 访问MySQL(转)

    在公司中经常会遇到部署多种数据库环境的情况,对于开发人员来说经常在不同数据库之间转换确实有些繁琐,本篇将介绍从SQL Server 操作MySQL 数据库的方法. 数据库测试环境 1. SQL Ser ...

  8. SQL Server :理解数据记录结构

    原文:SQL Server :理解数据记录结构 在SQL Server :理解数据页结构我们提到每条记录都有7 bytes的系统行开销,那这个7 bytes行开销到底是一个什么样的结构,我们一起来看下 ...

  9. SQL Server :理解数据页结构

    原文:SQL Server :理解数据页结构 我们都很清楚SQL Server用8KB 的页来存储数据,并且在SQL Server里磁盘 I/O 操作在页级执行.也就是说,SQL Server 读取或 ...

随机推荐

  1. Python之路- 反射&定制自己的数据类型

    一.isinstance和issubclass isinstance(obj,cls)检查是否obj是否是类 cls 的对象 issubclass(sub, super)检查sub类是否是 super ...

  2. [ SharePoint ADFS 开发部署系列 (一)]

    前言 本文完全原创,转载请说明出处,希望对大家有用. 随着企业信息化建设逐渐成熟,基于微软体系的企业内部系统架构在众多企业中得到应用,随之而来的用户统一身份认证(SSO)问题成为企业IT部门急需解决的 ...

  3. 简谈-Python一些常用的爬虫技巧

    第一种:基本的网页抓取 get方法 import urllib2url = "链接response = urllib2.urlopen(url)print response.read() p ...

  4. python练习_12

    题目:敏感词文本文件 filtered_words.txt,里面的内容 和 0011题一样,当用户输入敏感词语,则用 星号 * 替换,例如当用户输入「北京是个好城市」,则变成「**是个好城市」.(11 ...

  5. 纯HTML课表

    table标签构造课表 table标签常用于制作表格以及简单布局,于是我就玩了下table标签,用table标签也能构造出很漂亮的页面呢,虽然在博客页面加入与实际打开页面稍微有点出入,但还是可以接受的 ...

  6. android在myeclipse上创建的项目各种报错

    这几天被android弄得头疼死了.差不多把电脑弄了个遍. 先是离线安装ADT,下载ADT,然后配置,但是因为ADT与MyEclipse冲突.所以直接不要再myeclipse下弄Android的环境了 ...

  7. Laravel5中Cookie的使用

    今天在Laravel框架中使用Cookie的时候,碰到了点问题,自己被迷糊折腾了半多小时.期间研究了Cookie的实现类,也在网站找了许多的资料,包括问答.发现并没有解决问题.网上的答案都是互相抄袭, ...

  8. WPF 自定义ColorDialog DropDownCustomColorPicker

    今天分享一个 WPF 版的ColorDialog,该控件源自 这里,不过笔者已经该控件做了大量的修改工作,以适应自己的产品需求,闲话少说,先看看效果图: 1.DropDownCustomColorPi ...

  9. fgets()函数以及fputs()函数

    fgets() fgets() 该函数是一个文件操作相关的函数 暂时使用这个函数可以从键盘接收一个字符串,保存到字符数组中 原来接收字符串保存到数组中的方法: char str[50]; 1) sca ...

  10. percona-xtrabackup安装

    二进制包安装(推荐安装方式,不用安装依赖包,非常方便): 1.下载安二进制包:      wget https://www.percona.com/downloads/XtraBackup/Perco ...