惯用数据库的DML语句的比较和总结
DML = Data Manipulation Language, 数据操纵语言 ,使用户能够查询 数据库 以及操作已有数据库中的数据的计算机语言。具体是指是 UPDATE更新、 INSERT插入、 DELETE删除。
最近为了做新旧系统异构数据库的同步,另外为了确保新旧系统实现的业务功能更加趋于一致,所以有点小懒的我也啃了一段时间的旧系统的存储过程(旧系统的业务功能全部依赖 SQL Server中的存储过程,而新系统采用 Oracle数据库, 而且数据库语句都通过上层的业务编写),对一些 DML语句有一些总结和体会,分享给大家。
本文进行对比的地方基于常用的几种数据库: Oracle、 MySQL和 SQL Server。
1、 尽量避免不够通用的 SQL 语句
有一些语句写法只在某一种数据库中使用,而其余数据库会导致执行失败,若需要在编程时写 SQL语句,因为可能引起的数据库迁移问题,何不尽量避免这种迁移陷阱呢?
( 1 ) INSERT 后不加 INTO
在 INSERT后不加 INTO,在 SQL Server和 MySQL数据库都会执行成功,但 Oracle会提示“ ORA-00925: missing INTO keyword”的错误信息,例如:
( 2 ) DELETE 后不加 FROM
在 DELETE后不加 FROM的情况,在 SQL Server和 Oracle数据库中可以执行成功,但在 MySQL数据库中会提示“ SQL 执行错误 # 1064. 从数据库的响应 : You have an error in your SQL syntax; check the manual that corresponds to you’re my SQL server version from the right syntax to use near ‘…….’”,例如:
( 3 )获取当前时间
这三种数据库的都能定义 DATETIME(日期时间类型),但在 INSERT和 UPDATE等语句为这种类型的数据设值时所用的函数都各不相同。 MySQL使用 now()函数, SQL Server使用 GETDATE()函数, Oracle使用 sysdate。
例如在 MySQL中显示当前时间可使用语句:
在 Oracle中显示当前时间使用语句:
为了解决三者使用不一样的问题,一般的做法是在 Java使用 JDBC操作时,可以将当前时间通过 Java的方法得到,再给某个字段设置这个 java.sql.Date类型的值,参考代码如下:
String sql = " insert into testdate(createTime) values (?) " ;
ps = conn.prepareStatement(sql);
ps.setDate( 1 , new java.sql.Date(createTime.getTime()));
int re = ps.executeUpdate();
( 4 )自增主键的处理
在这三种数据库中都可以定义自增 ID作为主键,优点:节省时间,根本不用考虑怎么来标识唯一记录,写程序也简单了,数据库维护着这一批 ID号,在 INSERT语句时,如果所操作的表采用了自增主键,一般不需要指定这个字段。
缺点:在做分布式数据库时,要求数据同步时,这种自增 ID就会出现严重的问题,因为你无法用该 ID来唯一标识记录。同时在数据库做移植时,也会出现各种问题,总之,对此自增 ID有依赖的情况,都有可能出现问题。我就是深受其害的人之一。
解决的方法有很多,例如将主键定义成一个字符串类型,该字段交给上层业务来指定和保证唯一性,例如定义成流水号(里面带有日期时间和其它保证唯一性的值)。或者将主键使用 uniqueidentifier数据类型等。
2、 稍微复杂点的 DML 语句
( 1 ) INSERT 语句中各字段的值来自 SELECT 语句
INSERT 语句用于向表格中插入新的行,若按照数据库字段的排列顺序进行字段设值,可以在 INSERT语句中不指定字段名称,参考语法如下:
INSERT INTO 表名称 VALUES (值 1, 值 2,....)
因为上面的语句太依赖于字段的排序,为了导致迁移的一些不必要的问题,一般提倡指定所要插入数据的列,参考语法如下:
INSERT INTO表名称 ( 列 1, 列 2,...) VALUES (值 1, 值 2,....)
INSERT语句新行数据的全部字段的值或某些字段的值可以来自于对另一个表的查询语句。例如如下的语句将 userbarring中的 LimitType值为 0的记录插入到 userbarring_bak表中:
( 2 ) CASE……WHEN…… 语句
有些 INSERT或 UPDATE语句中带有 CASE……WHEN语句,举例如下:
INSERT INTO PLAT_UIDLine(UID,CallIn,CallOut,LastUpdateTime) VALUES (‘12345678’,(CASE @CallType WHEN 1 THEN 1 ELSE 0 END),(CASE @CallType WHEN 2 THEN 1 ELSE 0 END),GETDATE())
其中 CallType变量是存储过程定义的,在运行时它是确定的值。
待续。