3.3.3. DML
3.3.3.1. GaussDB-Oracle
3.3.3.1.1. 主键或唯一约束冲突时更新该条数据,否则插入数据
语法
REPLACE INTO table_name(column_name [, …])
VALUES(…) [,(…)]
| SELECT_SUB_QUERY
警告
- 统一SQL会将REPLACE INTO转为INSERT INTO…ON DUPLICATE KEY UPDATE,限制如下:
ON DUPLICATE KEY UPDATE执行更新操作,而REPLACE INTO执行删除和插入操作;
ON DUPLICATE KEY UPDATE只更新重复键所在行的列值,而REPLACE INTO插入完全新的数据;
ON DUPLICATE KEY UPDATE保留了非唯一键、主键的原始值,而REPLACE INTO将完全替换整行数据;
ON DUPLICATE KEY UPDATE不会重置自增字段的值,而REPLACE INTO会重置自增字段的值;
ON DUPLICATE KEY UPDATE 依赖REPLACE INTO语句中明确的列名。
示例
-- 转换前MySQL SQL:
replace into user_test(id,name) value (1,'zhangsan');
replace into tb1( name, title, mood) select rname, rtitle, rmood from tb2;
-- 转换后GaussDB-Oracle SQL:
INSERT INTO user_test (id,name) VALUES (1,'zhangsan') ON DUPLICATE KEY UPDATE id=VALUES(id),name=VALUES(name);
INSERT INTO tb1 (name,title,mood) SELECT rname,rtitle,rmood FROM tb2 ON DUPLICATE KEY UPDATE name=VALUES(name),title=VALUES(title),mood=VALUES(mood);
3.3.3.1.2. 主键或唯一约束冲突时更新该条数据,否则插入数据
语法
INSERT INTO table_name [(column1, ...)] VALUES (value1, ...) ON DUPLICATE KEY UPDATE column1=value2 [, ...];
示例
CREATE TABLE test_table (
id INT PRIMARY KEY,
name VARCHAR(20),
age INT
);
INSERT INTO test_table (id, name, age) VALUES (1, 'John', 25);
-- 转换前MySQL SQL:
INSERT INTO test_table (id, name, age) values (1, 'Make', 30) ON DUPLICATE KEY UPDATE name = 'Jam', age = 20;
-- 转换后GaussDB-Oracle SQL:
INSERT INTO test_table (id, name, age) VALUES (1, 'Make', 30) ON DUPLICATE KEY UPDATE name = 'Jam', age = 20;
3.3.3.1.3. 主键或唯一约束冲突时忽略不插入数据
语法
INSERT IGNORE INTO table_name [(column1, ...)] VALUES (value1, ...) [, ...];
示例
CREATE TABLE test_table (
id INT PRIMARY KEY,
name VARCHAR(20),
age INT
);
INSERT INTO test_table (id, name, age) VALUES (1, 'John', 25);
-- 转换前MySQL SQL:
INSERT IGNORE INTO test_table (id, name, age) values (1, 'Make', 30);
-- 转换后GaussDB-Oracle SQL:
INSERT INTO test_table (id, name, age) VALUES (1, 'Make', 30) ON DUPLICATE KEY UPDATE NOTHING;
3.3.3.1.4. 联表更新
语法
UPDATE [IGNORE] table1 [, table2] SET column1=value1 [, column2=value2] [where ...];
警告
不支持with子句组合;
联表更新时最多支持两张表更新;
当两张表更新时,SET列值时,列名必须带表名或表别名,例如 update…set a.id=1 或 update…set test_table.id=2。
UPDATE IGNORE xxx,转化时候可通过配置项[unisql.remove.ignore]的配置决定是否移除IGNORE
示例
-- 转换前MySQL SQL:
update t1 a, t2 b set a.name = 'join', b.name = 'make' where a.id = 5 and b.id = 6;
update t1 set name = 'join', age = '20' where id = 5;
-- 转换后GaussDB-Oracle SQL:
WITH sub_update_t2 AS (UPDATE t2 AS b SET b.name='make' FROM t1 AS a WHERE a.id=5 AND b.id=6 RETURNING b.name) UPDATE t1 AS a SET a.name='join' FROM t2 AS b WHERE a.id=5 AND b.id=6;
UPDATE t1 SET name='join', age='20' WHERE id=5;
-- 转换前MySQL SQL:
UPDATE IGNORE test_update_ignore
SET unique_column = 20, value_column = 'Updated Value'
WHERE id = 3;
-- 转换后GaussDB-Oracle SQL:
-- 配置项:unisql.remove.ignore=1
UPDATE test_update_ignore SET unique_column=20, value_column='Updated Value' WHERE id=3
-- 配置项:unisql.remove.ignore=0
UPDATE IGNORE test_update_ignore SET unique_column=20, value_column='Updated Value' WHERE id=3
3.3.3.1.5. 表删除
语法
-- 单表删除
DELETE FROM tbl_name [[AS] tbl_alias]
[WHERE where_condition]
[LIMIT row_count]
-- 多表删除
DELETE tbl_name[.*] [, tbl_name[.*]] ...
FROM table_references
[WHERE where_condition]
警告
- 单表删除目前限制:
where 中不支持order by、limit子句
- 多表删除目前限制:
where 中不支持order by、limit子句
不支持USING
联表删除单表时,delete 后面的名称必须和被删除的表名或别名完全一致
联表数量小于3张时,联表删除,必须是单表,不能是子查询
关联表为2张时,联表条件必须满足唯一性,不支持删除的表数量大于2;只支持cross join 和left join(left join时删除的表必须是第一个表的别名、连接的表必须是2个且都带有别名、必须是第一个表左连接第二个表);删除一张表时,删除的表必须是关联的第一张表;转换成with时with目前不支持双引号,因此删除的表名不能是关键字
关联表超过3张时,暂不支持
关联表为3张时,第一张表应为单表,只支持cross join,删除的表必须是关联的第一张表,子查询只能是一层
示例
-- 转换前MySQL SQL:
DELETE from test_table limit 10;
delete a from test_table a where a.id = 1;
delete a,b from test_table a,test_table b where a.id = b.id;
DELETE a FROM tb_ci_base_object a, tb_ci_communication_endpoint b WHERE a.instance_id = b.instance_id AND b.instance_id = '1';
DELETE tb_ci_base_object, tb_ci_communication_endpoint FROM tb_ci_base_object , tb_ci_communication_endpoint WHERE tb_ci_base_object.instance_id = tb_ci_communication_endpoint.instance_id AND tb_ci_communication_endpoint.instance_id = '1';
delete tb_rpa_flow_reference from tb_rpa_flow_reference,(select distinct to_flow_id from tb_rpa_flow_reference where root_flow_id = '1' union select '1' from dual) as b, (select distinct root_flow_id from tb_rpa_flow_reference where to_flow_id = '1' union select '1' from dual) as c where tb_rpa_flow_reference.from_flow_id = b.to_flow_id and tb_rpa_flow_reference.root_flow_id = c.root_flow_id;
-- 转换后GaussDB-Oracle SQL:
DELETE from test_table limit 10;
DELETE FROM test_table AS a WHERE a.id=1;
WITH a AS (DELETE FROM test_table AS a USING test_table AS b WHERE a.id=b.id RETURNING a.id) DELETE FROM test_table AS b USING a WHERE a.id=b.id;
DELETE FROM tb_ci_base_object AS a USING tb_ci_communication_endpoint AS b WHERE a.instance_id=b.instance_id AND b.instance_id='1';
WITH tb_ci_base_object AS (DELETE FROM tb_ci_base_object USING tb_ci_communication_endpoint WHERE tb_ci_base_object.instance_id=tb_ci_communication_endpoint.instance_id AND tb_ci_communication_endpoint.instance_id='1' RETURNING tb_ci_base_object.instance_id) DELETE FROM tb_ci_communication_endpoint USING tb_ci_base_object WHERE tb_ci_base_object.instance_id=tb_ci_communication_endpoint.instance_id;
DELETE FROM tb_rpa_flow_reference USING (SELECT DISTINCT to_flow_id FROM tb_rpa_flow_reference WHERE root_flow_id='1' UNION SELECT '1' FROM sys_dummy) AS b CROSS JOIN (SELECT DISTINCT root_flow_id FROM tb_rpa_flow_reference WHERE to_flow_id='1' UNION SELECT '1' FROM sys_dummy) AS c WHERE tb_rpa_flow_reference.from_flow_id=b.to_flow_id AND tb_rpa_flow_reference.root_flow_id=c.root_flow_id;
-- 转换前MySQL SQL:
DELETE FROM mysql.user WHERE user = 'xxx';
-- 目前GaussDB-Oracle不支持删除数据库用户,转换报错(CONVERT ERROR),不支持(not support),具体如下:
(CONVERT ERROR)
[ [00002]not support error: not support ]
3.3.3.1.6. 分页查询
语法
SELECT ... FROM ... LIMIT [offset,] row_count;
警告
offset取值从0开始,表从offset+1条记录行开始检索,rows代表取出rows条数据; 当offset不指定时,默认从第一条记录开始,取出rows行。
示例
-- 转换前MySQL SQL:
SELECT * FROM test_table LIMIT 5, 10;
SELECT * FROM test_table LIMIT 10;
-- 转换后GaussDB-Oracle SQL:
SELECT * FROM test_table LIMIT 5, 10;
SELECT * FROM test_table LIMIT 10;
3.3.3.1.7. 强制索引查询
语法
SELECT ... FROM ... FORCE INDEX(index_name [,index_name]...) WHERE ...;
警告
对于gaussdb自身不支持的SQL语法,统一SQL不做转换,例如gaussdb中cross join无需带on条件,inner join 必须带on条件,而mysql中无此限制。
示例
-- 转换前MySQL SQL:
SELECT * FROM employees FORCE INDEX (department_idx) WHERE department_id = 10;
select
tb.name,
tb.instance_id,
f.dest_instance_id,
f.source_instance_id
from
tb_ci_concrete_collection f force index(idx_source_instance)
left join tb_ci_base_object tb on
tb.instance_id = f.instance_id;
-- 转换后GaussDB-Oracle SQL:
SELECT /*+ IndexScan(employees department_idx)*/ * FROM employees WHERE department_id = 10;
SELECT /*+ IndexScan(f idx_source_instance)*/ tb.name,tb.instance_id,f.dest_instance_id,f.source_instance_id
FROM tb_ci_concrete_collection AS f LEFT JOIN tb_ci_base_object AS tb ON tb.instance_id = f.instance_id;
-- 转换前MySQL SQL,force index 支持多个索引
select
tb.name,
tb.instance_id,
f.dest_instance_id,
f.source_instance_id
from
tb_ci_concrete_collection f force index(idx_source_instance,idx_instance_id)
left join tb_ci_base_object tb on
tb.instance_id = f.instance_id;
-- 转换后GaussDB-Oracle SQL:
SELECT /*+ IndexScan(f idx_source_instance) IndexScan(f idx_instance_id)*/ tb.name,tb.instance_id,f.dest_instance_id,f.source_instance_id
FROM tb_ci_concrete_collection AS f LEFT JOIN tb_ci_base_object AS tb ON tb.instance_id=f.instance_id
3.3.3.1.8. 查看当前库所有表
语法
SHOW TABLES
示例
-- 转换前MySQL SQL:
SHOW TABLES;
-- 转换后GaussDB-Oracle SQL:
SELECT tablename FROM pg_tables WHERE schemaname=current_schema();
3.3.3.1.9. 查询分区表信息
语法
SELECT ... FROM INFORMATION_SCHEMA.PARTITIONS WHERE ...;
示例
-- 转换前MySQL SQL:
SELECT MAX(partition_description) FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_SCHEMA = 'public' AND TABLE_NAME = 'test_table';
-- 转换后GaussDB-Oracle SQL:
SELECT MAX(partition_description) FROM unisql.information_schema_partitions WHERE TABLE_SCHEMA='public' AND TABLE_NAME='test_table';
3.3.3.1.10. 空值判断
语法
警告
对于update、delete、select的where条件中对于列的判断条件,如果列值为空,则转化为IS NULL,如果列值不为空,则转化为IS NOT NULL。 因为在gaussdb-oracle中,null与空值’’等价,此行为与mysql有差异(在mysql中,null与空值’’不等价);
对于select的where条件中对于列等于的判断条件,如果列值等于绑定变量,如绑定变量的值为空,在配置文件unisql.conf中,配置unisql.null.table.columns表名和列名。在Java应用中,会将 where columnName = ? 转化成 where (columnName =? or (cast ? as dataType) is null and columnName is null);这里的dataType指字符的数据类型,本功能结合元数据来推导 列的数据类型,如果不同表名中有相同的列,且列的数据类型不同、不同表名在sql中有相同的别名,且列前面有这个相同的别名,可能会出现误转。 具体使用请参考 unisql.conf文件说明。
对于select的where条件中对于列不等于的判断条件,列值不等于绑定变量的转化功能暂不支持。
示例
-- 转换前MySQL SQL:
select * from tb_sys_param where status>0 and field !='' and field is not null;
select * from tb_sys_param where status>0 and field ='' and field is null;
-- 转换后GaussDB-Oracle SQL:
SELECT * FROM tb_sys_param WHERE status>0 AND field IS NOT NULL AND field IS NOT NULL;
SELECT * FROM tb_sys_param WHERE status>0 AND field IS NULL AND field IS NULL;
-- 准备数据:
CREATE TABLE c (
id INT AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(100),
content longtext,
created_at TIMESTAMP
);
INSERT INTO table2 (title, content, created_at) VALUES
(null, '', CURRENT_TIMESTAMP),
('', null, CURRENT_TIMESTAMP),
('', 'Content3', CURRENT_TIMESTAMP),
('Title4', null, CURRENT_TIMESTAMP),
('Title5', 'Content5', CURRENT_TIMESTAMP),
('Title6', 'Content6', CURRENT_TIMESTAMP),
('Title7', 'Content7', CURRENT_TIMESTAMP),
('Title8', 'Content8', CURRENT_TIMESTAMP),
('Title9', 'Content9', CURRENT_TIMESTAMP),
('Title10', 'Content10', CURRENT_TIMESTAMP);
-- 配置文件unisql.conf中,配置unisql.null.table.columns=table2:title;转换前MySQL SQL:
select
id,
title,
content,
created_at
from
table2
where
title = ? or content = ? order by id;
-- 转换后GaussDB-Oracle SQL:
SELECT id,title,content,created_at FROM table2 WHERE (title=? OR (CAST(? AS varchar) IS NULL AND title IS NULL)) OR content=? ORDER BY id
3.3.3.1.11. 删除用户
语法
DELETE FROM mysql.user WHERE user = 'user_name';
警告
受配置参数控制,config/unisql.conf中unisql.replace.sql参数可配置需要替换的sql语句。
示例
-- 转换前MySQL SQL:
DELETE FROM mysql.user WHERE user = '' or user = null;
-- 转换后GaussDB-Oracle SQL(unisql.replace.sql = 'select 1'):
select 1;
3.3.3.2. GoldenDB-Mysql
3.3.3.2.1. REPLACE INTO
语法
REPLACE INTO table_name(column_name [, …])
VALUES(…) [,(…)]
| SELECT_SUB_QUERY
警告
- 统一SQL会将REPLACE INTO转为MERGE INTO,限制如下:
需要开启参数
unisql.transform.replace.into
并配合 元数据管理 功能使用;目前仅支持源数据库为Mysql,目标数据库为GoldenDB-Mysql的场景;
目标表至少有一个唯一约束,且table_name(column_name [, …]) 的column_name包含至少一个唯一约束的所有列;
优先使用第一个约束名称为PRIMARY的约束,GoldenDB-Mysql中主键约束默认名称为PRIMARY;
当merge into 有多个唯一约束时,可能出现因其他约束冲突导致转化后的sql执行失败的问题;
values表达式只支持字面值,不支持子查询、函数、别名等。
示例
-- 转换前MySQL SQL:
REPLACE INTO B (id,name, value)
SELECT id as dd, 1, 'f' as ff FROM C;
-- 转换后GoldenDB-Mysql SQL:
MERGE INTO `B` AS `target_table`
USING (SELECT `id` AS `dd`,1 AS `name`,'f' AS `ff` FROM `C`) AS `source_table`
ON
(`target_table`.`id`=`source_table`.`dd`)
WHEN MATCHED THEN UPDATE SET
`name`=`source_table`.`name`,
`value`=`source_table`.`ff`
WHEN NOT MATCHED THEN
INSERT (`id`,`name`,`value`)
VALUES (`source_table`.`dd`,`source_table`.`name`,`source_table`.`ff`)
-- 转换前MySQL SQL:
REPLACE INTO B (id,name, value)
SELECT id, name, value FROM A WHERE A.ID=21 union
SELECT id, name, value FROM C WHERE C.ID=31;
-- 转换后GoldenDB-Mysql SQL:
MERGE INTO `B` AS `target_table`
USING
(SELECT `id` AS `id`,`name` AS `name`,`value` AS `value` FROM `A` WHERE `A`.`ID`=21
UNION
SELECT `id` AS `id`,`name` AS `name`,`value` AS `value` FROM `C` WHERE `C`.`ID`=31)
AS `source_table`
ON (`target_table`.`id`=`source_table`.`id`)
WHEN MATCHED THEN UPDATE
SET `name`=`source_table`.`name`,
`value`=`source_table`.`value`
WHEN NOT MATCHED THEN INSERT (`id`,`name`,`value`)
VALUES (`source_table`.`id`,`source_table`.`name`,`source_table`.`value`)
3.3.3.2.2. INSERT INTO … ON DUPLICATE KEY UPDATE
语法
INSERT
[INTO] tbl_name
[(col_name [, col_name] ...)]
{ {VALUES | VALUE} (value_list) [, (value_list)] ... }
[ON DUPLICATE KEY UPDATE assignment_list]
INSERT
[INTO] tbl_name
[(col_name [, col_name] ...)]
{ SELECT ...
| table_name
}
[ON DUPLICATE KEY UPDATE assignment_list]
警告
- 统一SQL会将INSERT INTO … ON DUPLICATE KEY UPDATE 转为MERGE INTO,限制如下:
需要开启参数
unisql.transform.replace.into
并配合 元数据管理 功能使用;目前仅支持源数据库为Mysql,目标数据库为GoldenDB-Mysql的场景;
主键自增问题,mysql中冲突后修改,自增键会跳跃增长。merge into只是修改,自增键不会增加。两边库的自增键会对应不上
插入的列必须有主键或唯一键(如果是联合主键或联合唯一键,联合的列需要全部写出;多个唯一键时所有唯一键都要列出),否则merge into 中on关联条件无法获取
mysql多个唯一键冲突时(不同的行数据)只会更新第一个冲突的唯一键所在行。merge into 中如果存在多个唯一键用or连接,冲突的行都会更新。两边数据结果不一致
insert into SELECT 子句查询出来的主键或唯一键存在重复行数据时,mysql可以执行,merge into执行报错(主键或唯一键重复)
merge into 中 on 关联条件组成:联合主键中的列之间、联合唯一键中的列之间用and连接,主键和唯一键之间、唯一键和唯一键之间用or连接;(用or连接目标库冲突的行都会更新,mysql只会更新第一个冲突所在行)
不支持更新多列, update (column,cloumn)=expr,expr
values表达式只支持字面值,不支持子查询、函数、别名等。
示例
-- 数据准备,使用前要加载元数据
CREATE TABLE `unisql_insert_duplicate_key_update_1` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`key` varchar(63) unique NOT null DEFAULT 'null' COMMENT '属性英文名',
`name` varchar(63) DEFAULT NULL COMMENT '属性描述',
`type` varchar(31) DEFAULT NULL COMMENT '类型',
`length` int(11) DEFAULT NULL COMMENT '长度',
`class_id` varchar(63) DEFAULT NULL COMMENT '所属类',
`mark_as_deleted` tinyint(1) DEFAULT NULL COMMENT '是否标记为删除',
`store_place` int(11) DEFAULT NULL COMMENT '存储位置',
`editable` tinyint(1) DEFAULT NULL COMMENT '是否可编辑',
`validate` varchar(512) DEFAULT NULL COMMENT '检验规则',
`user_defined` tinyint(1) DEFAULT NULL COMMENT '是否是自定义字段',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `unisql_insert_duplicate_key_update_1` (`key`, `name`, `type`, `length`, `class_id`, `mark_as_deleted`, `store_place`, `editable`, `validate`) VALUES
( 'encode', '编码', 'enum', '63', 'SEE.SYSTEM_FILE', '0', '1', '1', NULL),
( 'content', '内容', 'text', '0', 'SEE.SYSTEM_FILE', '0', '1', '1', NULL),
( 'file_path', '路径', 'varchar', '1023', 'SEE.SYSTEM_FILE', '0', '1', '1', NULL),
( 'file_extend', '格式', 'enum', '63', 'SEE.SYSTEM_FILE', '0', '1', '1', NULL),
( 'file_live_host', '宿主主机', 'varchar', '63', 'SEE.SYSTEM_FILE', '0', '1', '1', NULL),
( 'file_size', '文件大小', 'double', '0', 'SEE.SYSTEM_FILE', '0', '1', '1', NULL),
( 'keyword', '关键字', 'varchar', '1023', 'SEE.SYSTEM_FILE', '0', '1', '1', NULL),
( 'file_nature', '文件属性', 'enum', '31', 'SEE.SYSTEM_FILE', '0', '1', '1', NULL),
( 'file_system', '文件系统', 'varchar', '31', 'SEE.SYSTEM_FILE', '0', '1', '1', NULL);
-- 转换前MySQL SQL:
INSERT INTO `unisql_insert_duplicate_key_update_1` (`key`, `name`, `type`, `length`, `class_id`, `mark_as_deleted`, `store_place`, `editable`, `validate`) VALUES
( 'encode', '编码1', 'enum', '63', 'SEE.SYSTEM_FILE', '0', '1', '1', NULL)
ON DUPLICATE KEY UPDATE name=VALUES(name),`type`=VALUES(`type`),`length`=VALUES(`length`);
-- 转换后GoldenDB-Mysql SQL:
MERGE INTO `unisql_insert_duplicate_key_update_1` AS `unisql_insert_duplicate_key_update_1`
USING (SELECT 'encode' AS `key`,'编码1' AS `name`,'enum' AS `type`,'63' AS `length`,'SEE.SYSTEM_FILE' AS `class_id`,'0' AS `mark_as_deleted`,'1' AS `store_place`,'1' AS `editable`,NULL AS `validate` FROM DUAL)
AS `source_table`
ON (`unisql_insert_duplicate_key_update_1`.`key`=`source_table`.`key`)
WHEN MATCHED THEN
UPDATE SET `unisql_insert_duplicate_key_update_1`.`name`=`source_table`.`name`,`unisql_insert_duplicate_key_update_1`.`type`=`source_table`.`type`,
`unisql_insert_duplicate_key_update_1`.`length`=`source_table`.`length`
WHEN NOT MATCHED THEN
INSERT (`key`,`name`,`type`,`length`,`class_id`,`mark_as_deleted`,`store_place`,`editable`,`validate`)
VALUES (`source_table`.`key`,`source_table`.`name`,`source_table`.`type`,`source_table`.`length`,`source_table`.`class_id`,`source_table`.`mark_as_deleted`,`source_table`.`store_place`,
`source_table`.`editable`,`source_table`.`validate`)
-- 转换前MySQL SQL:
INSERT INTO `unisql_insert_duplicate_key_update_1` (`key`,`name`, `type`, `length`, `class_id`, `mark_as_deleted`, `store_place`, `editable`, `validate`)
select 'encode','编码' as name, 'enum1', '63', 'SEE.SYSTEM_FILE', '1', '0', '0', null from dual union
select 'encode','编码' as name, 'enum1', '64', 'SEE.SYSTEM_FILE', '1', '0', '0', null from dual
ON DUPLICATE KEY UPDATE name=VALUES(name),`type`=VALUES(`type`),`length`=VALUES(`length`),mark_as_deleted=unisql_insert_duplicate_key_update_1.mark_as_deleted,store_place= VALUES(store_place),validate= VALUES(validate);
-- 转换后GoldenDB-Mysql SQL:
MERGE INTO `unisql_insert_duplicate_key_update_1` AS `unisql_insert_duplicate_key_update_1`
USING (SELECT 'encode' AS `key`,'编码' AS `name`,'enum1' AS `type`,'63' AS `length`,'SEE.SYSTEM_FILE' AS `class_id`,'1' AS `mark_as_deleted`,'0' AS `store_place`,'0' AS `editable`,NULL AS `validate` FROM dual
UNION
SELECT 'encode' AS `key`,'编码' AS `name`,'enum1' AS `type`,'64' AS `length`,'SEE.SYSTEM_FILE' AS `class_id`,'1' AS `mark_as_deleted`,'0' AS `store_place`,'0' AS `editable`,NULL AS `validate` FROM dual)
AS `source_table`
ON (`unisql_insert_duplicate_key_update_1`.`key`=`source_table`.`key`)
WHEN MATCHED THEN
UPDATE SET `unisql_insert_duplicate_key_update_1`.`name`=`source_table`.`name`,`unisql_insert_duplicate_key_update_1`.`type`=`source_table`.`type`,`unisql_insert_duplicate_key_update_1`.`length`=`source_table`.`length`,
`unisql_insert_duplicate_key_update_1`.`mark_as_deleted`=`unisql_insert_duplicate_key_update_1`.`mark_as_deleted`,`unisql_insert_duplicate_key_update_1`.`store_place`=`source_table`.`store_place`,
`unisql_insert_duplicate_key_update_1`.`validate`=`source_table`.`validate`
WHEN NOT MATCHED THEN
INSERT (`key`,`name`,`type`,`length`,`class_id`,`mark_as_deleted`,`store_place`,`editable`,`validate`)
VALUES (`source_table`.`key`,`source_table`.`name`,`source_table`.`type`,`source_table`.`length`,`source_table`.`class_id`,`source_table`.`mark_as_deleted`,
`source_table`.`store_place`,`source_table`.`editable`,`source_table`.`validate`)
3.3.3.3. LightDB-Mysql
3.3.3.3.1. INSERT INTO
语法
INSERT
[INTO] tbl_name
[(col_name [, col_name] ...)]
{ {VALUES | VALUE} [ROW] ( value_list) [, [ROW] (value_list)] ... }
示例
CREATE TABLE test_table (
id INT PRIMARY KEY,
name VARCHAR(20) UNIQUE,
age INT
);
-- 转换前MySQL SQL:
INSERT INTO test_table (id, name, age) VALUES row (1, 'John', 25),row (2,'Tom',18);
-- 转换后LightDB-Mysql SQL:
INSERT INTO "test_table" ("id","name","age") VALUES (1,'John',25),(2,'Tom',18)
3.3.3.3.2. INSERT INTO … ON DUPLICATE KEY UPDATE
语法
INSERT
[INTO] tbl_name
[(col_name [, col_name] ...)]
{ {VALUES | VALUE} (value_list) [, (value_list)] ... }
[ON DUPLICATE KEY UPDATE assignment_list]
INSERT
[INTO] tbl_name
[(col_name [, col_name] ...)]
{ SELECT ...
| table_name
}
[ON DUPLICATE KEY UPDATE assignment_list]
警告
- 统一SQL会将INSERT INTO … ON DUPLICATE KEY UPDATE 转为INSERT INTO … ON CONFLICT …,限制如下:
需要配合 元数据管理 功能使用;
目前仅支持源数据库为Mysql,目标数据库为LightDB-Mysql的场景;
插入的表必须有主键或唯一键,否则ON CONFLICT 中冲突列无法获取;
冲突列会把主键和唯一键都会包含,所以当插入的组合列发生冲突时,更新现有记录;
assignment_list表达式右边支持vlaues函数转化为EXCLUDED相关列,其他表达式透传。
示例
CREATE TABLE test_table (
id INT PRIMARY KEY,
name VARCHAR(20) UNIQUE,
age INT
);
INSERT INTO test_table (id, name, age) VALUES (1, 'John', 25);
-- 转换前MySQL SQL:
INSERT INTO test_table (id, name, age) values (1, 'John', 30) ON DUPLICATE KEY UPDATE name = values(name), age = values(age);
-- 转换后LightDB-Mysql SQL:
INSERT INTO "t1" ("id","name","age") VALUES (1,'John', 30) ON CONFLICT ("id","name") DO UPDATE SET "name"=EXCLUDED."name","age"=EXCLUDED."age"
3.3.3.3.3. INSERT IGNORE INTO
语法
INSERT IGNORE INTO table_name [(column1, ...)] VALUES (value1, ...) [, ...];
示例
CREATE TABLE test_table (
id INT PRIMARY KEY,
name VARCHAR(20),
age INT
);
INSERT INTO test_table (id, name, age) VALUES (1, 'John', 25);
-- 转换前MySQL SQL:
INSERT IGNORE INTO test_table (id, name, age) values (1, 'Make', 30);
-- 转换后LightDB-Mysql SQL:
INSERT INTO "test_table" ("id","name","age") VALUES (1,'Make',30) ON CONFLICT DO NOTHING
3.3.3.3.4. update
语法
[ WITH with_query [, ...] ]
UPDATE table_references
[FROM table_references]
SET assignment_list
[WHERE where_condition]
[RETURNING ReturningClause]
警告
- 统一SQL会将UPDATE多表更新语句转为WITH … UPDATE语句,限制如下:
目前仅支持源数据库为Mysql,目标数据库为LightDB-Mysql的场景;
更新表对象必须是2个以上;
示例
-- 转换前MySQL SQL:
UPDATE
tb_ci_base_object a, my_table c
SET
a.instance_id = a.instance_id,
a.name = 'John',
a.age = 30,
a.last_modified = '2025-01-01',
a.version = round(a.version + 0.01, 2),
c.instance_id = c.instance_id,
c.name = 'John',
c.age = 11,
c.last_modified = '2025-01-01',
c.version = round(c.version + 0.01, 2)
WHERE
a.instance_id = c.instance_id AND c.instance_id = 123;
-- 转换后Lightdb-Mysql SQL:
WITH `c` AS (
UPDATE
`my_table` AS `c`
SET
`c`.`instance_id` = `c`.`instance_id`,
`c`.`name` = 'John',
`c`.`age` = 11,
`c`.`last_modified` = '2025-01-01',
`c`.`version` = round(`c`.`version` + 0.01, 2)
FROM
`tb_ci_base_object` AS `a`
WHERE
`a`.`instance_id` = `c`.`instance_id`
AND `c`.`instance_id` = 123
RETURNING `c`.*
)
UPDATE
`tb_ci_base_object` AS `a`
SET
`a`.`instance_id` = `a`.`instance_id`,
`a`.`name` = 'John',
`a`.`age` = 30,
`a`.`last_modified` = '2025-01-01',
`a`.`version` = round(`a`.`version` + 0.01, 2)
FROM
`c`
WHERE
`a`.`instance_id` = `c`.`instance_id`
AND `c`.`instance_id` = 123;
3.3.3.3.5. REPLACE INTO
语法
统一SQL会将REPLACE INTO 转为INSERT INTO … ON CONFLICT DO UPDATE SET…
REPLACE [INTO] tbl_name
[(col_name [, col_name] ...)]
{ {VALUES | VALUE} (value_list) [, (value_list)] ...
|
VALUES row_constructor_list
}
REPLACE
[INTO] tbl_name
SET assignment_list
REPLACE
[INTO] tbl_name
[(col_name [, col_name] ...)]
{SELECT ... | TABLE table_name}
value:
{expr | DEFAULT}
value_list:
value [, value] ...
row_constructor_list:
ROW(value_list)[, ROW(value_list)][, ...]
assignment:
col_name = value
assignment_list:
assignment [, assignment] ...
警告
- 统一SQL会将REPLACE INTO 转为INSERT INTO … ON CONFLICT DO UPDATE SET…,限制如下:
需要配合 元数据管理 功能使用;
目前仅支持源数据库为MySQL,目标数据库为LightDB-MySQL的场景;
插入的表必须有主键或唯一键,不支持主键和唯一键同时存在,否则ON CONFLICT 中冲突列无法获取;
主键自增问题,MySQL中冲突后是先删除再插入,而LightDB-MySQL冲突后是更新列内容,所以两边库自增列会对应不上。
REPLACE INTO … select XXX … 时SELECT的列必须写明确,不能SELECT * ,并且SELECT 出来的列类型需要和插入表的列保持一致。
示例
CREATE TABLE tb_rolepower (
role_id varchar(32) NOT NULL,
asset_type varchar(64) DEFAULT NULL,
power_id varchar(64) NOT NULL,
sys_key varchar(32) NOT NULL DEFAULT 'acm',
PRIMARY KEY (role_id, power_id, sys_key)
);
INSERT INTO tb_rolepower (role_id, asset_type, power_id, sys_key) VALUES ('see_default_read_write_role', 'menu', 'POWER_PAASMANAGE_SYSTEM_SET', 'paasmanage');
-- 转换前MySQL SQL:
REPLACE INTO tb_rolepower(role_id, asset_type, power_id, sys_key) VALUES ('see_default_read_role', 'menu', 'AUTO_JOBNET', 'auto');
-- 转换后LightDB-Mysql SQL:
INSERT INTO "tb_rolepower" ("role_id","asset_type","power_id","sys_key") VALUES ('see_default_read_role','menu','AUTO_JOBNET','auto')
ON CONFLICT ("role_id","power_id","sys_key")
DO UPDATE SET "role_id"=EXCLUDED."role_id","asset_type"=EXCLUDED."asset_type","power_id"=EXCLUDED."power_id","sys_key"=EXCLUDED."sys_key"
-- 转换前MySQL SQL:
REPLACE INTO tb_rolepower(role_id, asset_type, power_id, sys_key) VALUES ROW('see_default_read_role', 'menu', 'AUTO_JOBNET', 'auto');
-- 转换后LightDB-Mysql SQL:
INSERT INTO "tb_rolepower" ("role_id","asset_type","power_id","sys_key") VALUES ('see_default_read_role','menu','AUTO_JOBNET','auto')
ON CONFLICT ("role_id","power_id","sys_key")
DO UPDATE SET "role_id"=EXCLUDED."role_id","asset_type"=EXCLUDED."asset_type","power_id"=EXCLUDED."power_id","sys_key"=EXCLUDED."sys_key"
-- 转换前MySQL SQL:
replace into tb_rolepower (role_id, asset_type, power_id, sys_key) select DISTINCT role_id, asset_type, 'POWER_MYSQL_CANCLE', sys_key from tb_rolepower where power_id = 'POWER_PAASMANAGE_SYSTEM_SET';
-- 转换后LightDB-Mysql SQL:
INSERT INTO "tb_rolepower" ("role_id","asset_type","power_id","sys_key") SELECT DISTINCT "role_id","asset_type",'POWER_MYSQL_CANCLE',"sys_key" FROM "tb_rolepower" WHERE "power_id"='POWER_PAASMANAGE_SYSTEM_SET'
ON CONFLICT ("role_id","power_id","sys_key")
DO UPDATE SET "role_id"=EXCLUDED."role_id","asset_type"=EXCLUDED."asset_type","power_id"=EXCLUDED."power_id","sys_key"=EXCLUDED."sys_key"
-- 转换前MySQL SQL:
REPLACE tb_rolepower SET role_id = 'see_default_read_write_role', asset_type = 'menu', power_id = 'AUTO_JOBNET', sys_key = 'auto';
-- 转换后LightDB-Mysql SQL:
INSERT INTO "tb_rolepower" ("role_id","asset_type","power_id","sys_key") VALUES ('see_default_read_write_role','menu','AUTO_JOBNET','auto')
ON CONFLICT ("role_id","power_id","sys_key")
DO UPDATE SET "role_id"=EXCLUDED."role_id","asset_type"=EXCLUDED."asset_type","power_id"=EXCLUDED."power_id","sys_key"=EXCLUDED."sys_key"
3.3.3.4. OceanBase-Mysql
3.3.3.4.1. INSERT INTO
语法
INSERT
[INTO] tbl_name
[(col_name [, col_name] ...)]
{ {VALUES | VALUE} [ROW] ( value_list) [, [ROW] (value_list)] ... }
示例
CREATE TABLE test_table (
id INT PRIMARY KEY,
name VARCHAR(20) UNIQUE,
age INT
);
-- 转换前MySQL SQL:
INSERT INTO test_table (id, name, age) VALUES row (1, 'John', 25),row (2,'Tom',18);
-- 转换后LightDB-Mysql SQL:
INSERT INTO test_table (id,name,age) VALUES (1,'John',25),(2,'Tom',18)
3.3.3.4.2. REPLACE INTO
语法
REPLACE [INTO] tbl_name
[(col_name [, col_name] ...)]
{ {VALUES | VALUE} (value_list) [, (value_list)] ...
|
VALUES row_constructor_list
}
REPLACE
[INTO] tbl_name
SET assignment_list
REPLACE
[INTO] tbl_name
[(col_name [, col_name] ...)]
{SELECT ... | TABLE table_name}
value:
{expr | DEFAULT}
value_list:
value [, value] ...
row_constructor_list:
ROW(value_list)[, ROW(value_list)][, ...]
assignment:
col_name = value
assignment_list:
assignment [, assignment] ...
示例
CREATE TABLE tb_rolepower (
role_id varchar(32) NOT NULL,
asset_type varchar(64) DEFAULT NULL,
power_id varchar(64) NOT NULL,
sys_key varchar(32) NOT NULL DEFAULT 'acm',
PRIMARY KEY (role_id, power_id, sys_key)
);
INSERT INTO tb_rolepower (role_id, asset_type, power_id, sys_key) VALUES ('see_default_read_write_role', 'menu', 'POWER_PAASMANAGE_SYSTEM_SET', 'paasmanage');
-- 转换前MySQL SQL:
REPLACE INTO tb_rolepower(role_id, asset_type, power_id, sys_key) VALUES ('see_default_read_role', 'menu', 'AUTO_JOBNET', 'auto');
-- 转换后OceanBase-Mysql SQL:
REPLACE INTO `tb_rolepower` (`role_id`,`asset_type`,`power_id`,`sys_key`) VALUES ('see_default_read_role','menu','AUTO_JOBNET','auto')
-- 转换前MySQL SQL:
REPLACE INTO tb_rolepower(role_id, asset_type, power_id, sys_key) VALUES ROW('see_default_read_role', 'menu', 'AUTO_JOBNET', 'auto');
-- 转换后OceanBase-Mysql SQL:
REPLACE INTO `tb_rolepower` (`role_id`,`asset_type`,`power_id`,`sys_key`) VALUES ('see_default_read_role','menu','AUTO_JOBNET','auto')
-- 转换前MySQL SQL:
replace into tb_rolepower (role_id, asset_type, power_id, sys_key) select DISTINCT role_id, asset_type, 'POWER_MYSQL_CANCLE', sys_key from tb_rolepower where power_id = 'POWER_PAASMANAGE_SYSTEM_SET';
-- 转换后OceanBase-Mysql SQL:
REPLACE INTO `tb_rolepower` (`role_id`,`asset_type`,`power_id`,`sys_key`) SELECT DISTINCT `role_id`,`asset_type`,'POWER_MYSQL_CANCLE',`sys_key` FROM `tb_rolepower` WHERE `power_id`='POWER_PAASMANAGE_SYSTEM_SET'
-- 转换前MySQL SQL:
REPLACE tb_rolepower SET role_id = 'see_default_read_write_role', asset_type = 'menu', power_id = 'AUTO_JOBNET', sys_key = 'auto';
-- 转换后OceanBase-Mysql SQL:
REPLACE INTO `tb_rolepower` SET `role_id`='see_default_read_write_role',`asset_type`='menu',`power_id`='AUTO_JOBNET',`sys_key`='auto'
3.3.3.4.3. DELETE 单表
语法
DELETE [IGNORE]
FROM tbl_name [[AS] table_alias]
[WHERE where_condition]
[ORDER BY {col_name | expr | position}
[ASC | DESC], ...]
[LIMIT row_count]
示例
CREATE TABLE test_table (
id INT PRIMARY KEY,
name VARCHAR(20) UNIQUE,
age INT
);
-- 转换前MySQL SQL:
DELETE IGNORE FROM test_table as t WHERE t.id = 1 ORDER BY t.id limit 10;
-- 转换后OceanBase-Mysql SQL:
DELETE FROM `test_table` AS `t` WHERE `t`.`id`=1 ORDER BY `t`.`id` LIMIT 10;
3.3.3.4.4. DELETE 多表
语法
DELETE [IGNORE]
[tbl_name|table_alias][.*] [, [tbl_name|table_alias][.*]]...
FROM tbl_name [[AS] table_alias] [, tbl_name[AS] table_alias]...
[WHERE where_condition]
示例
CREATE TABLE person (
id INT PRIMARY KEY,
name VARCHAR(20),
age INT
);
CREATE TABLE job (
id INT PRIMARY KEY,
job VARCHAR(20)
);
-- 转换前MySQL SQL:
DELETE IGNORE p, j FROM person as p, job as j WHERE p.id = j.id;
-- 转换后OceanBase-Mysql SQL:
DELETE `p`,`j` FROM `person` AS `p`, `job` AS `j` WHERE `p`.`id`=`j`.`id`;
3.3.3.4.5. DELETE 单表
语法
DELETE [IGNORE]
FROM tbl_name [[AS] table_alias]
[WHERE where_condition]
[ORDER BY {col_name | expr | position}
[ASC | DESC], ...]
[LIMIT row_count]
示例
CREATE TABLE test_table (
id INT PRIMARY KEY,
name VARCHAR(20) UNIQUE,
age INT
);
-- 转换前MySQL SQL:
DELETE IGNORE FROM test_table as t WHERE t.id = 1 ORDER BY t.id limit 10;
-- 转换后Lightdb-Mysql SQL:
DELETE FROM "test_table" AS "t" WHERE "t"."id"=1 ORDER BY "t"."id" LIMIT 10;
3.3.3.4.6. DELETE 多表
语法
DELETE [IGNORE]
[tbl_name|table_alias][.*] [, [tbl_name|table_alias][.*]]...
FROM tbl_name [[AS] table_alias] [, tbl_name[AS] table_alias]...
[WHERE where_condition]
示例
CREATE TABLE person (
id INT PRIMARY KEY,
name VARCHAR(20),
age INT
);
CREATE TABLE job (
id INT PRIMARY KEY,
job VARCHAR(20)
);
-- 转换前MySQL SQL:
DELETE IGNORE p, j FROM person as p, job as j WHERE p.id = j.id;
-- 转换后Lightdb-Mysql SQL:
WITH "j" AS (DELETE FROM "job" AS "j" USING "person" AS "p" WHERE "p"."id"="j"."id" RETURNING "j".*) DELETE FROM "person" AS "p" USING "job" AS "j" WHERE "p"."id"="j"."id";
3.3.3.5. Oracle_19C
3.3.3.5.1. INSERT INTO
语法
INSERT [IGNORE]
[INTO] tbl_name
[(col_name [, col_name] ...)]
{ {VALUES | VALUE} (value_list) [, (value_list)] ... }
[ON DUPLICATE KEY UPDATE assignment_list]
INSERT [IGNORE]
[INTO] tbl_name
[(col_name [, col_name] ...)]
{ SELECT ... }
[ON DUPLICATE KEY UPDATE assignment_list]
value_list:
value [, value] ...
assignment:
col_name = values(col_name)
assignment_list:
assignment [, assignment] ...
示例
CREATE TABLE test_table (
id INT PRIMARY KEY auto_increment,
name VARCHAR(20) UNIQUE,
age INT
);
-- 转换前MySQL SQL:
INSERT INTO test_table (name, age) VALUES ('John', 25);
INSERT INTO test_table (id,name, age) VALUES (10,'Tom', 26);
INSERT INTO test_table (name, age) VALUES ('Jerry', 27);
select id,name, age from test_table;
id|name |age|
--+-----+---+
1|John | 25|
10|Tom | 26|
11|Jerry| 27|
-- 转换后Oracle_19C SQL:
INSERT INTO test_table (name,age) VALUES ('John',25);
INSERT INTO test_table (id,name,age) VALUES (10,'Tom',26);
INSERT INTO test_table (name,age) VALUES ('Jerry',27);
SELECT id,name,age FROM test_table
ID|NAME |AGE|
--+-----+---+
1|John | 25|
10|Tom | 26|
2|Jerry| 27|
--插入多行、子查询
CREATE TABLE test_cases (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(10),
age INT,
is_active BOOLEAN
);
-- 转换前MySQL SQL:
INSERT INTO test_cases (name, age, is_active) VALUES
('Multi1', 18, TRUE),
('Multi2', 19, FALSE);
INSERT INTO test_cases (name, age, is_active) with tmp as (select name, age, is_active from test_cases) select name, age+1, is_active from tmp;
-- 转换后Oracle_19C SQL:
INSERT INTO test_cases (name,age,is_active) SELECT 'Multi1',18,1 FROM DUAL UNION ALL SELECT 'Multi2',19,0 FROM DUAL;
INSERT INTO test_cases (name,age,is_active) WITH tmp AS (SELECT name,age,is_active FROM test_cases) SELECT name,age+1,is_active FROM tmp;
--insert ignore ... 、insert ... on duplicate key update
CREATE TABLE insert_ignore_unisql (
id int PRIMARY KEY NOT NULL,
key_id varchar(64) unique NOT null,
class_id varchar(63) DEFAULT NULL ,
mark_id varchar(31) DEFAULT NULL,
store_id int DEFAULT NULL ,
user_defined int DEFAULT NULL);
INSERT INTO insert_ignore_unisql (id, key_id, class_id, mark_id, store_id, user_defined) VALUES
(1, 'key_001', 'class_A', 'mark_1', 100, 1),
(2, 'key_002', 'class_B', 'mark_2', 101, 2),
(3, 'key_003', 'class_C', 'mark_3', 102, 3),
(4, 'key_004', 'class_D', 'mark_4', 103, 4),
(5, 'key_005', 'class_E', 'mark_5', 104, 5);
-- 转换前MySQL SQL:
INSERT ignore INTO insert_ignore_unisql (id, key_id, class_id, mark_id, store_id, user_defined) VALUES
(1, 'key_001', 'class_A', 'mark_1', 100, 1),
(7, 'key_001', 'class_H', 'mark_7', 107, 7);
INSERT IGNORE INTO insert_ignore_unisql (id, key_id, class_id, mark_id, store_id, user_defined) VALUES
(5, 'key_005_1', 'class_E_1', 'mark_5_1', 1041, 51),
(8, 'key_008', 'class_H', 'mark_8',108, 8)
ON DUPLICATE KEY UPDATE
class_id = VALUES(class_id),
mark_id = VALUES(mark_id),
store_id = VALUES(store_id),
user_defined = VALUES(user_defined);
-- 转换后Oracle_19C SQL:
MERGE INTO insert_ignore_unisql target_table USING
(SELECT 1 AS id,'key_001' AS key_id,'class_A' AS class_id,'mark_1' AS mark_id,100 AS store_id,1 AS user_defined FROM DUAL UNION
SELECT 7 AS id,'key_001' AS key_id,'class_H' AS class_id,'mark_7' AS mark_id,107 AS store_id,7 AS user_defined FROM DUAL)
source_table ON ((target_table.id=source_table.id) OR (target_table.key_id=source_table.key_id))
WHEN NOT MATCHED THEN INSERT (id,key_id,class_id,mark_id,store_id,user_defined) VALUES
(source_table.id,source_table.key_id,source_table.class_id,source_table.mark_id,source_table.store_id,source_table.user_defined);
MERGE INTO insert_ignore_unisql target_table USING
(SELECT 5 AS id,'key_005_1' AS key_id,'class_E_1' AS class_id,'mark_5_1' AS mark_id,1041 AS store_id,51 AS user_defined FROM DUAL UNION
SELECT 8 AS id,'key_008' AS key_id,'class_H' AS class_id,'mark_8' AS mark_id,108 AS store_id,8 AS user_defined FROM DUAL) source_table
ON ((target_table.id=source_table.id) OR (target_table.key_id=source_table.key_id))
WHEN MATCHED THEN UPDATE SET
target_table.class_id=source_table.class_id,target_table.mark_id=source_table.mark_id,
target_table.store_id=source_table.store_id,target_table.user_defined=source_table.user_defined
WHEN NOT MATCHED THEN INSERT (id,key_id,class_id,mark_id,store_id,user_defined)
VALUES (source_table.id,source_table.key_id,source_table.class_id,source_table.mark_id,source_table.store_id,source_table.user_defined)
警告
在 MySQL 中,如果表的主键是自增列(AUTO_INCREMENT),即使手动指定了 id 的值,后续的自动分配仍会基于手动指定的最大值递增,确保连续性。 而在 Oracle 19C 中手动指定 id 后,SEQUENCE 的下一个值仍然基于其自身的递增逻辑,与手动插入的最大 id 无关。自增序列插入null 不支持,oracle中序列不支持null; 对于boolean类型的插入not true , not false不支持;
- 统一SQL会将INSERT IGNORE 转为 MERGE INTO,限制如下:
需要配合 元数据管理 功能使用;
主键自增问题,MySQL中冲突后是自增键会跳跃增长,出现跳号,所以两边库自增列会对应不上;
插入的列必须有主键或唯一键(如果是联合主键或联合唯一键,联合的列需要全部写出;多个唯一键时所有唯一键都要列出),否则转化为普通insert into语句;
INSERT IGNORE SELECT 子句不支持使用 select * ;
mysql插入的数据中的对应的主键或唯一键存在重复行数据时,mysql可以执行,merge into执行报错(主键或唯一键重复)
INSERT IGNORE 转为 MERGE INTO只支持了主键或唯一键冲突,其他check约束、外键等暂不支持。
- 统一SQL会将INSERT … ON DUPLICATE KEY UPDATE 转为 MERGE INTO,限制如下:
需要配合 元数据管理 功能使用;
主键自增问题,MySQL中冲突后是自增键会跳跃增长,出现跳号,所以两边库自增列会对应不上;
mysql有冲突时所有列都支持更新,MERGE INTO 中UPDATE SET不支持更新主键和唯一键;
插入的列必须有主键或唯一键(如果是联合主键或联合唯一键,联合的列需要全部写出;多个唯一键时所有唯一键都要列出),否则转化为普通insert into语句;
insert into SELECT 子句不支持使用 select * ;
mysql插入语句中一行数据冲突表中多行数据,只会更新第一个冲突的唯一键所在行。MERGE INTO 中如果存在多个唯一键用or连接,冲突的行都会更新。两边数据结果不一致;
mysql插入的数据中的对应的主键或唯一键存在重复行数据时,mysql可以执行,merge into执行报错(主键或唯一键重复);
ON DUPLICATE KEY UPDATE不支持更新主键,唯一键的列(merge into 中不支持更新ON 子句中引用的列);
INSERT … ON DUPLICATE KEY UPDATE 转为 MERGE INTO只支持了主键或唯一键冲突,其他check约束、外键等暂不支持。
on duplicate update仅考虑 colName= values(colName)这种情况
- 统一SQL多发比对在如上转换的限制上还有如下限制:
不支持列只有自增键一个字段的情况,不支持空和null问题
插入的列必须有主键或唯一键(如果是联合主键或联合唯一键,联合的列需要全部写出;多个唯一键时所有唯一键都要列出),否则merge into 中on关联条件无法获取
mysql多个唯一键冲突时(不同的行数据)只会更新第一个冲突的唯一键所在行。merge into 中如果存在多个唯一键用or连接,冲突的行都会更新。两边数据结果不一致
insert into SELECT 子句查询出来的主键或唯一键存在重复行数据时,mysql可以执行,merge into执行报错(主键或唯一键重复)
values表达式只支持字面值,不支持子查询、函数、别名等
ON DUPLICATE KEY UPDATE不支持更新主键,唯一键的列(merge into 中不支持更新ON 子句中引用的列);更新的列在插入列中必须存在
boolean类型 not true , not false不支持
自增序列插入null 不支持,oracle中序列不支持null
mysql和oracle两库之间null的排序规则不一致
不支持limit;mysql中LIMIT不支持和IN/ALL/ANY/SOME subquery 一起使用
3.3.3.5.2. REPLACE INTO
语法
统一SQL会将REPLACE INTO 转为 MERGE INTO 语句,支持语法如下:
REPLACE [INTO] tbl_name
[(col_name [, col_name] ...)]
{ {VALUES | VALUE} (value_list) [, (value_list)] ...}
REPLACE
[INTO] tbl_name
[(col_name [, col_name] ...)]
{SELECT ...}
value:
{expr | DEFAULT}
value_list:
value [, value] ...
assignment:
col_name = value
assignment_list:
assignment [, assignment] ...
警告
- 统一SQL会将REPLACE INTO 转为 MERGE INTO,限制如下:
需要配合 元数据管理 功能使用;
主键自增问题,MySQL中冲突后是先删除再插入,而ORACLE冲突后是更新列内容,所以两边库自增列会对应不上。
mysql有冲突时所有列都支持更新,MERGE INTO 中on关联条件字段不支持更新(主键和唯一键不支持更新)
REPLACE INTO … select XXX … 时SELECT的列必须写明确,不能SELECT * ,并且SELECT 出来的列类型需要和插入表的列保持一致。
mysql多个唯一键冲突时(不同的行数据)只会更新第一个冲突的唯一键所在行。MERGE INTO 中如果存在多个唯一键用or连接,冲突的行都会更新。两边数据结果不一致
REPLACE INTO 指定的插入列中必须包含至少一个完整的唯一约束。
示例
create table students_1(
id int primary key,
name varchar(10),
age int);
-- 转换前MySQL SQL:
replace into students_1(id,name,age) values(4,'yodo',18);
-- 转换后Oracle SQL:
MERGE INTO students_1 insert_table USING (SELECT 4 AS id,'yodo' AS name,18 AS age FROM DUAL) source_table ON (insert_table.id=source_table.id) WHEN MATCHED THEN UPDATE SET name=source_table.name,age=source_table.age WHEN NOT MATCHED THEN INSERT (id,name,age) VALUES (source_table.id,source_table.name,source_table.age);
-- 转换前MySQL SQL:
replace into students_1(id,name,age) values(5,'yodo',18),(6, 'mike', 20);
-- 转换后Oracle SQL:
MERGE INTO students_1 insert_table USING (SELECT 5 AS id,'yodo' AS name,18 AS age FROM DUAL UNION ALL SELECT 6 AS id,'mike' AS name,20 AS age FROM DUAL) source_table ON (insert_table.id=source_table.id) WHEN MATCHED THEN UPDATE SET name=source_table.name,age=source_table.age WHEN NOT MATCHED THEN INSERT (id,name,age) VALUES (source_table.id,source_table.name,source_table.age);
-- 转换前MySQL SQL:
replace into students_4(id, name, age) select id, name, age from students_5 where id<3;
-- 转换后Oracle SQL:
MERGE INTO students_4 insert_table USING (SELECT id AS id,name AS name,age AS age FROM students_5 WHERE id<3) source_table ON (insert_table.id=source_table.id AND insert_table.name=source_table.name) WHEN MATCHED THEN UPDATE SET age=source_table.age WHEN NOT MATCHED THEN INSERT (id,name,age) VALUES (source_table.id,source_table.name,source_table.age);
3.3.3.5.3. UPDATE 单表
语法
UPDATE [IGNORE] tbl_name
SET assignment_list
[WHERE where_condition]
[ORDER BY {col_name | expr | position}
[ASC | DESC], ...]
[LIMIT row_count]
示例
CREATE TABLE test_table (
id INT PRIMARY KEY auto_increment,
name VARCHAR(20) UNIQUE,
age INT
);
-- 转换前MySQL SQL:
update test_table set name = 'John' where id = 1;
update test_table set name = (select 'John' from dual) where id = 1;
update test_table set name = 'John' order by id limit 1;
--- 更新非唯一键
update ignore test_table set name = 'John' where id = 1;
--- 更新唯一键
update ignore test_table set id =2 where id=1;
-- 转换后Oracle_19C SQL:
UPDATE test_table SET name='John' WHERE id=1
UPDATE test_table SET name=(SELECT 'John' FROM dual) WHERE id=1
UPDATE test_table SET name='John' WHERE rowid IN (SELECT test_table.rowid AS rid FROM test_table ORDER BY id FETCH NEXT 1 ROWS ONLY );
--- 更新非唯一键
UPDATE test_table SET name='John' WHERE id=1;
--- 更新唯一键
MERGE INTO test_table target_table
USING (SELECT test_table.rowid AS rid,2 AS v0,row_number() OVER (PARTITION BY test_table.rowid ORDER BY test_table.rowid) AS rn FROM test_table WHERE id=1) source_table
ON (source_table.rid=target_table.rowid AND source_table.rn=1)
WHEN MATCHED THEN
UPDATE SET target_table.id=source_table.v0
WHERE NOT EXISTS (SELECT 1 FROM test_table filter_table WHERE filter_table.ID=source_table.v0)
警告
- 统一SQL对单表update可能转为merge into,限制如下:
不支持在一条SQL中把两行记录的唯一键更新为相同值,转换会成功,在oracle 执行会失败,比如:1,2 都更新为3,在mysql 其中某一条数据会被更新为3,在oracle 会更新失败
3.3.3.5.4. UPDATE 多表
语法
UPDATE [IGNORE] table_references
SET assignment_list
[WHERE where_condition]
示例
CREATE TABLE test_table (
id INT PRIMARY KEY auto_increment,
name VARCHAR(20) UNIQUE,
age INT
);
CREATE TABLE test_table1 (
id INT PRIMARY KEY auto_increment,
name VARCHAR(20) UNIQUE,
age INT
);
-- 转换前MySQL SQL:
update test_table a, test_table1 b set a.name = b.name where a.id= b.id and b.name = 'John';
update ignore test_table a, test_table1 b set a.id = 100 where a.id= b.id and b.name = 'John';
update test_table a, test_table1 b set a.age=15, b.age=15 where a.id= b.id and b.name = 'John';
update ignore test_table a, test_table1 b set a.id=100, b.name='jake' where a.id= b.id and b.name = 'John';
-- 转换后Oracle_19C SQL:
--- 多表更新转为merge into
MERGE INTO test_table target_table
USING (
SELECT
a.rowid AS rid,
b.name AS v0,
ROW_NUMBER() OVER (PARTITION BY a.rowid
ORDER BY
a.rowid) AS rn
FROM
test_table a ,
test_table1 b
WHERE
a.id = b.id
AND b.name = 'John') source_table
ON(source_table.rid = target_table.rowid AND source_table.rn = 1)
WHEN MATCHED THEN
UPDATE SET target_table.name = source_table.v0;
--- 多表更新带ignore转为merge into + not exists
MERGE INTO test_table target_table
USING (
SELECT
a.rowid AS rid,
100 AS v0,
row_number() OVER (PARTITION BY a.rowid
ORDER BY
a.rowid) AS rn
FROM
test_table a ,
test_table1 b
WHERE
a.id = b.id
AND b.name = 'John') source_table
ON(source_table.rid = target_table.rowid AND source_table.rn = 1)
WHEN MATCHED THEN
UPDATE SET target_table.id = source_table.v0
WHERE NOT EXISTS (
SELECT
1
FROM
test_table filter_table
WHERE
filter_table.ID = source_table.v0);
--- 更新多表转为匿名块
DECLARE
CURSOR cur_date IS SELECT a.rowid AS a_rid,b.rowid AS b_rid,15 AS a_v0,15 AS b_v0 FROM test_table a , test_table1 b WHERE a.id=b.id AND b.name='John';
BEGIN
FOR rec IN cur_date LOOP
UPDATE test_table a SET a.age=rec.a_v0 WHERE rowid = rec.a_rid;
UPDATE test_table1 b SET b.age=rec.b_v0 WHERE rowid = rec.b_rid;
END LOOP;
END;
--- 更新多表带ignore转为匿名块 + not exists
DECLARE
CURSOR cur_date IS SELECT a.rowid AS a_rid,b.rowid AS b_rid,100 AS a_v0,100 AS b_v0 FROM test_table a , test_table1 b WHERE a.id=b.id AND b.name='John';
BEGIN
FOR rec IN cur_date LOOP
UPDATE test_table a SET a.id=rec.a_v0 WHERE rowid = rec.a_rid AND NOT EXISTS (SELECT 1 FROM test_table filter_table WHERE filter_table.ID=rec.b_v0);
UPDATE test_table1 b SET b.id=rec.b_v0 WHERE rowid = rec.b_rid;
END LOOP;
END;
警告
- 统一SQL会将多表update转为merge into 或匿名块,限制如下:
更新字段必须指定表名,不指定不支持转换
不支持在一条SQL中把两行记录的唯一键更新为相同值,转换会成功,在oracle 执行会失败,比如:1,2 都更新为3,在mysql 其中某一条数据会被更新为3,在oracle 会更新失败
3.3.3.5.5. DELETE 单表
语法
DELETE [IGNORE]
FROM tbl_name [[AS] table_alias]
[WHERE where_condition]
示例
CREATE TABLE test_table (
id INT PRIMARY KEY,
name VARCHAR(20) UNIQUE,
age INT
);
-- 转换前MySQL SQL:
DELETE IGNORE FROM test_table as t WHERE t.id = 1;
-- 转换后Oracle_19C SQL:
DELETE FROM test_table t WHERE t.id = 1;
3.3.3.6. OceanBase-Oracle
3.3.3.6.1. INSERT INTO
语法
INSERT
[INTO] tbl_name
[(col_name [, col_name] ...)]
VALUES ( value_expr )
示例
CREATE TABLE test_table (
id INT PRIMARY KEY auto_increment,
name VARCHAR(20) UNIQUE,
age INT
);
-- 转换前MySQL SQL:
INSERT INTO test_table (name, age) VALUES ('John', 25);
INSERT INTO test_table (id,name, age) VALUES (10,'Tom', 26);
INSERT INTO test_table (name, age) VALUES ('Jerry', 27);
select id,name, age from test_table;
id|name |age|
--+-----+---+
1|John | 25|
10|Tom | 26|
11|Jerry| 27|
-- 转换后OceanBase-Oracle SQL:
INSERT INTO test_table (name,age) VALUES ('John',25);
INSERT INTO test_table (id,name,age) VALUES (10,'Tom',26);
INSERT INTO test_table (name,age) VALUES ('Jerry',27);
SELECT id,name,age FROM test_table
ID|NAME |AGE|
--+-----+---+
1|John | 25|
10|Tom | 26|
2|Jerry| 27|
警告
在 MySQL 中,如果表的主键是自增列(AUTO_INCREMENT),即使手动指定了 id 的值,后续的自动分配仍会基于手动指定的最大值递增,确保连续性。 而在 OceanBase-Oracle 中手动指定 id 后,SEQUENCE 的下一个值仍然基于其自身的递增逻辑,与手动插入的最大 id 无关。
3.3.3.6.2. UPDATE 单表
语法
UPDATE [IGNORE] tbl_name
SET assignment_list
[WHERE where_condition]
[ORDER BY {col_name | expr | position}
[ASC | DESC], ...]
[LIMIT row_count]
示例
CREATE TABLE test_table (
id INT PRIMARY KEY auto_increment,
name VARCHAR(20) UNIQUE,
age INT
);
-- 转换前MySQL SQL:
update test_table set name = 'John' where id = 1;
update test_table set name = (select 'John' from dual) where id = 1;
update test_table set name = 'John' order by id limit 1;
--- 更新非唯一键
update ignore test_table set name = 'John' where id = 1;
--- 更新唯一键
update ignore test_table set id =2 where id=1;
-- 转换后Oracle_19C SQL:
UPDATE test_table SET name='John' WHERE id=1
UPDATE test_table SET name=(SELECT 'John' FROM dual) WHERE id=1
UPDATE test_table SET name='John' WHERE rowid IN (SELECT test_table.rowid AS rid FROM test_table ORDER BY id FETCH NEXT 1 ROWS ONLY );
--- 更新非唯一键
UPDATE test_table SET name='John' WHERE id=1;
--- 更新唯一键
MERGE INTO test_table target_table
USING (SELECT test_table.rowid AS rid,2 AS v0,row_number() OVER (PARTITION BY test_table.rowid ORDER BY test_table.rowid) AS rn FROM test_table WHERE id=1) source_table
ON (source_table.rid=target_table.rowid AND source_table.rn=1)
WHEN MATCHED THEN
UPDATE SET target_table.id=source_table.v0
WHERE NOT EXISTS (SELECT 1 FROM test_table filter_table WHERE filter_table.ID=source_table.v0)
警告
- 统一SQL对单表update可能转为merge into,限制如下:
不支持在一条SQL中把两行记录的唯一键更新为相同值,转换会成功,在oracle 执行会失败,比如:1,2 都更新为3,在mysql 其中某一条数据会被更新为3,在oracle 会更新失败
3.3.3.6.3. UPDATE 多表
语法
UPDATE [IGNORE] table_references
SET assignment_list
[WHERE where_condition]
示例
CREATE TABLE test_table (
id INT PRIMARY KEY auto_increment,
name VARCHAR(20) UNIQUE,
age INT
);
CREATE TABLE test_table1 (
id INT PRIMARY KEY auto_increment,
name VARCHAR(20) UNIQUE,
age INT
);
-- 转换前MySQL SQL:
update test_table a, test_table1 b set a.name = b.name where a.id= b.id and b.name = 'John';
update ignore test_table a, test_table1 b set a.id = 100 where a.id= b.id and b.name = 'John';
update test_table a, test_table1 b set a.age=15, b.age=15 where a.id= b.id and b.name = 'John';
update ignore test_table a, test_table1 b set a.id=100, b.name='jake' where a.id= b.id and b.name = 'John';
-- 转换后Oracle_19C SQL:
--- 多表更新转为merge into
MERGE INTO test_table target_table
USING (
SELECT
a.rowid AS rid,
b.name AS v0,
ROW_NUMBER() OVER (PARTITION BY a.rowid
ORDER BY
a.rowid) AS rn
FROM
test_table a ,
test_table1 b
WHERE
a.id = b.id
AND b.name = 'John') source_table
ON(source_table.rid = target_table.rowid AND source_table.rn = 1)
WHEN MATCHED THEN
UPDATE SET target_table.name = source_table.v0;
--- 多表更新带ignore转为merge into + not exists
MERGE INTO test_table target_table
USING (
SELECT
a.rowid AS rid,
100 AS v0,
row_number() OVER (PARTITION BY a.rowid
ORDER BY
a.rowid) AS rn
FROM
test_table a ,
test_table1 b
WHERE
a.id = b.id
AND b.name = 'John') source_table
ON(source_table.rid = target_table.rowid AND source_table.rn = 1)
WHEN MATCHED THEN
UPDATE SET target_table.id = source_table.v0
WHERE NOT EXISTS (
SELECT
1
FROM
test_table filter_table
WHERE
filter_table.ID = source_table.v0);
--- 更新多表转为匿名块
DECLARE
CURSOR cur_date IS SELECT a.rowid AS a_rid,b.rowid AS b_rid,15 AS a_v0,15 AS b_v0 FROM test_table a , test_table1 b WHERE a.id=b.id AND b.name='John';
BEGIN
FOR rec IN cur_date LOOP
UPDATE test_table a SET a.age=rec.a_v0 WHERE rowid = rec.a_rid;
UPDATE test_table1 b SET b.age=rec.b_v0 WHERE rowid = rec.b_rid;
END LOOP;
END;
--- 更新多表带ignore转为匿名块 + not exists
DECLARE
CURSOR cur_date IS SELECT a.rowid AS a_rid,b.rowid AS b_rid,100 AS a_v0,100 AS b_v0 FROM test_table a , test_table1 b WHERE a.id=b.id AND b.name='John';
BEGIN
FOR rec IN cur_date LOOP
UPDATE test_table a SET a.id=rec.a_v0 WHERE rowid = rec.a_rid AND NOT EXISTS (SELECT 1 FROM test_table filter_table WHERE filter_table.ID=rec.b_v0);
UPDATE test_table1 b SET b.id=rec.b_v0 WHERE rowid = rec.b_rid;
END LOOP;
END;
警告
- 统一SQL会将多表update转为merge into 或匿名块,限制如下:
更新字段必须指定表名,不指定不支持转换
不支持在一条SQL中把两行记录的唯一键更新为相同值,转换会成功,在oracle 执行会失败,比如:1,2 都更新为3,在mysql 其中某一条数据会被更新为3,在oracle 会更新失败
3.3.3.6.4. DELETE 单表
语法
DELETE [IGNORE]
FROM tbl_name [[AS] table_alias]
[WHERE where_condition]
示例
CREATE TABLE test_table (
id INT PRIMARY KEY,
name VARCHAR(20) UNIQUE,
age INT
);
-- 转换前MySQL SQL:
DELETE IGNORE FROM test_table as t WHERE t.id = 1;
-- 转换后OceanBase-Oracle SQL:
DELETE FROM test_table t WHERE t.id = 1;