注册
多数据库关键字兼容性测试报告(DM / Oracle / MySQL / PostgreSQL / SQL Server)重点对比达梦和Oracle
培训园地/ 文章详情 /

多数据库关键字兼容性测试报告(DM / Oracle / MySQL / PostgreSQL / SQL Server)重点对比达梦和Oracle

lifetimebloved 2026/05/07 463 0 0

1. 测试背景与目的

在多数据库环境或数据库迁移场景中,不同数据库对关键字(Keyword)的保留程度及使用限制存在差异,可能导致对象创建失败或SQL兼容性问题。
本次测试旨在系统性梳理 DM、Oracle、MySQL、PostgreSQL、SQL Server 四类数据库中关键字的使用限制,验证其是否支持作为表名、字段名及函数名使用,为数据库设计规范制定及异构迁移提供参考依据。

2. 测试范围

image.png
3.测试对象

1. 所有数据库内置关键字
2. 测试维度:
   - 表名
   - 字段名
   - 函数名
3. 测试方式:
   - 不加引号
   - 加引号(数据库标准转义)

3. 测试方法

本次测试采用自动化脚本方式进行验证,核心方法如下:
3.1 从各数据库系统视图中获取关键字集合:
◦ DM: v$reserved_words
◦ Oracle:v$reserved_words
◦ MySQL:information_schema.keywords
◦ PostgreSQL:pg_get_keywords()
◦ SQL Server:基于官方关键字列表构建
3.2. 针对每个关键字,构造动态SQL进行测试:
◦ 创建表(关键字作为表名)
◦ 创建表(关键字作为字段名)
◦ 创建函数(关键字作为函数名)
3.3. 分别测试以下两种场景:
◦ 不使用转义(直接使用关键字)
◦ 使用转义(Oracle/PG使用双引号,MySQL使用反引号,SQL Server使用方括号)
3.4. 捕获执行结果:
◦ 成功:记录为支持
◦ 失败:记录错误信息(语法错误/关键字冲突等)
3.5. 将结果统一写入结果表,并导出为CSV进行分析对比。

统一结果表(可以跨库使用)

CREATE TABLE keyword_test_result (
    db_type     VARCHAR(20), -- Oracle/Sqlserver/mysql/postgres
    keyword     VARCHAR(100),
    test_type   VARCHAR(20),   -- TABLE / COLUMN / FUNCTION
    result      VARCHAR(10),
    error_msg   VARCHAR(4000),
    test_time   DATETIME
);

3.1 MySQL

3.1.1 关键词来源

select keyword from information_schema.keywords;

select count(*) from information_schema.keywords;
一共747个关键词

3.1.2存储过程(添加引号)

DELIMITER $$

CREATE PROCEDURE p_mysql_keyword()
BEGIN
    DECLARE done INT DEFAULT 0;
    DECLARE v_keyword VARCHAR(100);
    DECLARE v_err TEXT DEFAULT NULL;
    DECLARE stmt_ready INT DEFAULT 0;

    DECLARE cur CURSOR FOR
        SELECT WORD FROM INFORMATION_SCHEMA.KEYWORDS;

    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;

    OPEN cur;

    read_loop: LOOP
        FETCH cur INTO v_keyword;
        IF done THEN
            LEAVE read_loop;
        END IF;

        /* =====================================================
           TABLE 
        ===================================================== */
        SET v_err = NULL;
        SET stmt_ready = 0;

        BEGIN
            DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET v_err = 'TABLE_FAIL';

            SET @s = CONCAT('CREATE TABLE `', v_keyword, '` (id INT)');

            PREPARE stmt FROM @s;
            SET stmt_ready = 1;
            EXECUTE stmt;
            DEALLOCATE PREPARE stmt;

            SET @s = CONCAT('DROP TABLE IF EXISTS `', v_keyword, '`');
            PREPARE stmt FROM @s;
            EXECUTE stmt;
            DEALLOCATE PREPARE stmt;

            INSERT INTO keyword_test_result
            VALUES ('mysql', v_keyword, 'TABLE', 'OK', NULL, NOW());

        END;

        IF v_err IS NOT NULL THEN
            INSERT INTO keyword_test_result
            VALUES ('mysql', v_keyword, 'TABLE', 'FAIL', v_err, NOW());
        END IF;

        /* =====================================================
           COLUMN 测试
        ===================================================== */
        SET v_err = NULL;
        SET stmt_ready = 0;

        BEGIN
            DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET v_err = 'COLUMN_FAIL';

            SET @s = CONCAT('CREATE TABLE t_tmp (`', v_keyword, '` INT)');

            PREPARE stmt FROM @s;
            SET stmt_ready = 1;
            EXECUTE stmt;
            DEALLOCATE PREPARE stmt;

            DROP TABLE IF EXISTS t_tmp;

            INSERT INTO keyword_test_result
            VALUES ('mysql', v_keyword, 'COLUMN', 'OK', NULL, NOW());

        END;

        IF v_err IS NOT NULL THEN
            INSERT INTO keyword_test_result
            VALUES ('mysql', v_keyword, 'COLUMN', 'FAIL', v_err, NOW());
        END IF;

        /* =====================================================
           FUNCTION
        ===================================================== */
        SET v_err = NULL;
        SET stmt_ready = 0;

        BEGIN
            DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET v_err = 'FUNCTION_FAIL';

            /* CREATE FUNCTION */
            SET @s = CONCAT(
                'CREATE FUNCTION `', v_keyword, '`(x INT) ',
                'RETURNS INT DETERMINISTIC RETURN x'
            );

            PREPARE stmt FROM @s;
            SET stmt_ready = 1;
            EXECUTE stmt;
            DEALLOCATE PREPARE stmt;

            SET @s = CONCAT('DROP FUNCTION IF EXISTS `', v_keyword, '`');

            PREPARE stmt FROM @s;
            EXECUTE stmt;
            DEALLOCATE PREPARE stmt;

            INSERT INTO keyword_test_result
            VALUES ('mysql', v_keyword, 'FUNCTION', 'OK', NULL, NOW());

        END;

        IF stmt_ready = 1 THEN
            BEGIN
                DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN END;
                DEALLOCATE PREPARE stmt;
            END;
        END IF;

        IF v_err IS NOT NULL THEN
            INSERT INTO keyword_test_result
            VALUES ('mysql', v_keyword, 'FUNCTION', 'FAIL', v_err, NOW());
        END IF;

    END LOOP;

    CLOSE cur;
END$$

DELIMITER ;

3.1.3 存储过程(不加引号)

DELIMITER $$

CREATE PROCEDURE p_mysql_keyword()
BEGIN
    DECLARE done INT DEFAULT 0;
    DECLARE v_keyword VARCHAR(100);
    DECLARE v_err TEXT DEFAULT NULL;
    DECLARE stmt_ready INT DEFAULT 0;

    DECLARE cur CURSOR FOR
        SELECT WORD FROM INFORMATION_SCHEMA.KEYWORDS;

    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;

    OPEN cur;

    read_loop: LOOP
        FETCH cur INTO v_keyword;
        IF done THEN
            LEAVE read_loop;
        END IF;

        /* =====================================================
        ==================================================== */
        SET v_err = NULL;
        SET stmt_ready = 0;

        BEGIN
            DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET v_err = 'TABLE_FAIL';

            SET @s = CONCAT('CREATE TABLE `', v_keyword, '` (id INT)');

            PREPARE stmt FROM @s;
            SET stmt_ready = 1;
            EXECUTE stmt;
            DEALLOCATE PREPARE stmt;

            SET @s = CONCAT('DROP TABLE IF EXISTS `', v_keyword, '`');
            PREPARE stmt FROM @s;
            EXECUTE stmt;
            DEALLOCATE PREPARE stmt;

            INSERT INTO keyword_test_result
            VALUES ('mysql', v_keyword, 'TABLE', 'OK', NULL, NOW());

        END;

        IF v_err IS NOT NULL THEN
            INSERT INTO keyword_test_result
            VALUES ('mysql', v_keyword, 'TABLE', 'FAIL', v_err, NOW());
        END IF;


        SET v_err = NULL;
        SET stmt_ready = 0;

        BEGIN
            DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET v_err = 'COLUMN_FAIL';

            SET @s = CONCAT('CREATE TABLE t_tmp (`', v_keyword, '` INT)');

            PREPARE stmt FROM @s;
            SET stmt_ready = 1;
            EXECUTE stmt;
            DEALLOCATE PREPARE stmt;

            DROP TABLE IF EXISTS t_tmp;

            INSERT INTO keyword_test_result
            VALUES ('mysql', v_keyword, 'COLUMN', 'OK', NULL, NOW());

        END;

        IF v_err IS NOT NULL THEN
            INSERT INTO keyword_test_result
            VALUES ('mysql', v_keyword, 'COLUMN', 'FAIL', v_err, NOW());
        END IF;

        /* =====================================================
           FUNCTION
        ===================================================== */
        SET v_err = NULL;
        SET stmt_ready = 0;

        BEGIN
            DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET v_err = 'FUNCTION_FAIL';

            /* CREATE FUNCTION */
            SET @s = CONCAT(
                'CREATE FUNCTION `', v_keyword, '`(x INT) ',
                'RETURNS INT DETERMINISTIC RETURN x'
            );

            PREPARE stmt FROM @s;
            SET stmt_ready = 1;
            EXECUTE stmt;
            DEALLOCATE PREPARE stmt;

            SET @s = CONCAT('DROP FUNCTION IF EXISTS `', v_keyword, '`');

            PREPARE stmt FROM @s;
            EXECUTE stmt;
            DEALLOCATE PREPARE stmt;

            INSERT INTO keyword_test_result
            VALUES ('mysql', v_keyword, 'FUNCTION', 'OK', NULL, NOW());

        END;

        IF stmt_ready = 1 THEN
            BEGIN
                DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN END;
                DEALLOCATE PREPARE stmt;
            END;
        END IF;

        IF v_err IS NOT NULL THEN
            INSERT INTO keyword_test_result
            VALUES ('mysql', v_keyword, 'FUNCTION', 'FAIL', v_err, NOW());
        END IF;

    END LOOP;

    CLOSE cur;
END$$

DELIMITER ;

3.1.4 执行结果

添加引号的执行结果

mysql> call p_mysql_keyword()
    -> ;
Query OK, 0 rows affected (53.82 sec)

mysql> select database();
+------------+
| database() |
+------------+
| hzh        |
+------------+
1 row in set (0.00 sec)

mysql> select count(*),test_type from keyword_test_result where result='OK' group by test_type;
+----------+-----------+
| count(*) | test_type |
+----------+-----------+
|      747 | TABLE     |
|      747 | COLUMN    |
|      747 | FUNCTION  |
+----------+-----------+

不加引号执行结果

mysql> call p_mysql_raw_keyword();
Query OK, 0 rows affected (46.08 sec)

mysql> select count(*),result,test_type from keyword_test_result where db_type='mysql_raw'
    -> group by result,test_type;
+----------+--------+-----------+
| count(*) | result | test_type |
+----------+--------+-----------+
|      261 | FAIL   | TABLE     |
|      261 | FAIL   | COLUMN    |
|      747 | FAIL   | FUNCTION  |
|      486 | OK     | TABLE     |
|      486 | OK     | COLUMN    |
+----------+--------+-----------+
5 rows in set (0.01 sec)

从执行结果
1.mysql所有的关键词使用引号以后都可以作为表名table_name、字段column_name、函数名function_name
2.mysql所有的关键词不使用引号详情如下:

MySQL关键词失败详情.xlsx

3.2 PostgreSQL

3.2.1 关键词来源

PostgreSQL 没有官方关键字表
使用函数获取

SELECT word FROM pg_get_keywords();

select count(*) from pg_get_keywords();
#一共457个关键词

3.2.2 存储过程(关键词添加引号)

CREATE OR REPLACE PROCEDURE p_pg_keyword()
LANGUAGE plpgsql
AS $$
DECLARE
    r RECORD;
    v_sql TEXT;
BEGIN
    FOR r IN SELECT word FROM pg_get_keywords() LOOP

        BEGIN
            v_sql := format('CREATE TABLE %I (id INT)', r.word);
            EXECUTE v_sql;

            EXECUTE format('DROP TABLE %I', r.word);

            INSERT INTO keyword_test_result
            VALUES ('pg', r.word, 'TABLE', 'OK', NULL, now());

        EXCEPTION WHEN OTHERS THEN
            INSERT INTO keyword_test_result
            VALUES ('pg', r.word, 'TABLE', 'FAIL', SQLERRM, now());
        END;

        BEGIN
            v_sql := format('CREATE TABLE t_tmp (%I INT)', r.word);
            EXECUTE v_sql;

            EXECUTE 'DROP TABLE IF EXISTS t_tmp';

            INSERT INTO keyword_test_result
            VALUES ('pg', r.word, 'COLUMN', 'OK', NULL, now());

        EXCEPTION WHEN OTHERS THEN
            INSERT INTO keyword_test_result
            VALUES ('pg', r.word, 'COLUMN', 'FAIL', SQLERRM, now());
        END;

 BEGIN
    v_sql := format(
        'CREATE FUNCTION %I(x INT) RETURNS INT AS $func$ BEGIN RETURN x; END; $func$ LANGUAGE plpgsql',
        r.word
    );
    EXECUTE v_sql;

    EXECUTE format('DROP FUNCTION IF EXISTS %I(INT)', r.word);

    INSERT INTO keyword_test_result
    VALUES ('pg', r.word, 'FUNCTION', 'OK', NULL, now());

EXCEPTION WHEN OTHERS THEN
    INSERT INTO keyword_test_result
    VALUES ('pg', r.word, 'FUNCTION', 'FAIL', SQLERRM, now());
END;

    END LOOP;
END;
$$;

3.2.3 存储过程(关键词不添加引号)

CREATE OR REPLACE PROCEDURE p_pg_raw_keyword()
LANGUAGE plpgsql
AS $$
DECLARE
    r RECORD;
    v_sql TEXT;
BEGIN
    FOR r IN SELECT word FROM pg_get_keywords() LOOP

        /* ================= TABLE ================= */
        BEGIN
            v_sql := 'CREATE TABLE ' || r.word || ' (id INT)';
            EXECUTE v_sql;

            EXECUTE 'DROP TABLE ' || r.word;

            INSERT INTO keyword_test_result
            VALUES ('pg_raw', r.word, 'TABLE', 'OK', NULL, now());

        EXCEPTION WHEN OTHERS THEN
            INSERT INTO keyword_test_result
            VALUES ('pg_raw', r.word, 'TABLE', 'FAIL', SQLERRM, now());
        END;

        /* ================= COLUMN ================= */
        BEGIN
            v_sql := 'CREATE TABLE t_tmp (' || r.word || ' INT)';
            EXECUTE v_sql;

            EXECUTE 'DROP TABLE IF EXISTS t_tmp';

            INSERT INTO keyword_test_result
            VALUES ('pg_raw', r.word, 'COLUMN', 'OK', NULL, now());

        EXCEPTION WHEN OTHERS THEN
            INSERT INTO keyword_test_result
            VALUES ('pg_raw', r.word, 'COLUMN', 'FAIL', SQLERRM, now());
        END;

        /* ================= FUNCTION ================= */
        BEGIN
            v_sql :=
                'CREATE FUNCTION ' || r.word || '(x INT) RETURNS INT AS $func$ ' ||
                'BEGIN RETURN x; END; $func$ LANGUAGE plpgsql';

            EXECUTE v_sql;

            EXECUTE 'DROP FUNCTION IF EXISTS ' || r.word || '(INT)';

            INSERT INTO keyword_test_result
            VALUES ('pg_raw', r.word, 'FUNCTION', 'OK', NULL, now());

        EXCEPTION WHEN OTHERS THEN
            INSERT INTO keyword_test_result
            VALUES ('pg_raw', r.word, 'FUNCTION', 'FAIL', SQLERRM, now());
        END;

    END LOOP;
END;
$$;

3.2.3 执行结果

添加引号的执行结果

postgres=# select count(*),test_type from keyword_test_result where result='OK' group by test_type;
 count | test_type
-------+-----------
   457 | TABLE
   457 | FUNCTION
   457 | COLUMN
(3 rows)

不加引号的执行结果
image.png
从结果来看所有PostgreSQL所有的关键词使用引号都可以作为表名table_name、字段column_name、函数名function_name
如果不添加引号创建失败的关键词如下:
PG不加引号关键失败详情.xlsx

3.3 SqlServer mssql

3.3.1. 关键字来源

sqlserver目前没有系统试图和系统表能查出完整的关键字
可以考虑自己创建一张表

    id INT IDENTITY(1,1) PRIMARY KEY,
    db_type VARCHAR(50),
    keyword VARCHAR(200),
    create_time DATETIME DEFAULT GETDATE()
);

INSERT INTO db_keywords (db_type, keyword)
VALUES
('SQLSERVER','ADD'),
('SQLSERVER','ALL'),
('SQLSERVER','ALTER'),
('SQLSERVER','AND'),
('SQLSERVER','ANY'),
('SQLSERVER','AS'),
('SQLSERVER','ASC'),
('SQLSERVER','AUTHORIZATION'),
('SQLSERVER','BACKUP'),
('SQLSERVER','BEGIN'),
('SQLSERVER','BETWEEN'),
('SQLSERVER','BREAK'),
('SQLSERVER','BROWSE'),
('SQLSERVER','BULK'),
('SQLSERVER','BY'),
('SQLSERVER','CASCADE'),
('SQLSERVER','CASE'),
('SQLSERVER','CHECK'),
('SQLSERVER','CHECKPOINT'),
('SQLSERVER','CLOSE'),
('SQLSERVER','CLUSTERED'),
('SQLSERVER','COALESCE'),
('SQLSERVER','COLLATE'),
('SQLSERVER','COLUMN'),
('SQLSERVER','COMMIT'),
('SQLSERVER','COMPUTE'),
('SQLSERVER','CONSTRAINT'),
('SQLSERVER','CONTAINS'),
('SQLSERVER','CONTINUE'),
('SQLSERVER','CONVERT'),
('SQLSERVER','CREATE'),
('SQLSERVER','CROSS'),
('SQLSERVER','CURRENT'),
('SQLSERVER','DATABASE'),
('SQLSERVER','DBCC'),
('SQLSERVER','DECLARE'),
('SQLSERVER','DEFAULT'),
('SQLSERVER','DELETE'),
('SQLSERVER','DESC'),
('SQLSERVER','DISTINCT'),
('SQLSERVER','DROP'),
('SQLSERVER','EXEC'),
('SQLSERVER','EXECUTE'),
('SQLSERVER','EXISTS'),
('SQLSERVER','FROM'),
('SQLSERVER','FULL'),
('SQLSERVER','FUNCTION'),
('SQLSERVER','GRANT'),
('SQLSERVER','GROUP'),
('SQLSERVER','HAVING'),
('SQLSERVER','IN'),
('SQLSERVER','INDEX'),
('SQLSERVER','INNER'),
('SQLSERVER','INSERT'),
('SQLSERVER','INTERSECT'),
('SQLSERVER','INTO'),
('SQLSERVER','IS'),
('SQLSERVER','JOIN'),
('SQLSERVER','LEFT'),
('SQLSERVER','LIKE'),
('SQLSERVER','NOT'),
('SQLSERVER','NULL'),
('SQLSERVER','ON'),
('SQLSERVER','OR'),
('SQLSERVER','ORDER'),
('SQLSERVER','OUTER'),
('SQLSERVER','PRIMARY'),
('SQLSERVER','PROCEDURE'),
('SQLSERVER','RETURN'),
('SQLSERVER','RIGHT'),
('SQLSERVER','ROLLBACK'),
('SQLSERVER','SELECT'),
('SQLSERVER','SET'),
('SQLSERVER','TABLE'),
('SQLSERVER','THEN'),
('SQLSERVER','TO'),
('SQLSERVER','TRANSACTION'),
('SQLSERVER','TRIGGER'),
('SQLSERVER','UNION'),
('SQLSERVER','UNIQUE'),
('SQLSERVER','UPDATE'),
('SQLSERVER','USER'),
('SQLSERVER','VALUES'),
('SQLSERVER','VIEW'),
('SQLSERVER','WHERE'),
('SQLSERVER','WHILE'),
('SQLSERVER','WITH');

3.3.2 存储过程(添加引号)

CREATE PROCEDURE p_sqlserver_keyword
AS
BEGIN
    DECLARE @keyword NVARCHAR(100);
    DECLARE @sql NVARCHAR(MAX);

    DECLARE cur CURSOR FOR
        SELECT keyword FROM keyword_list;

    OPEN cur;
    FETCH NEXT FROM cur INTO @keyword;

    WHILE @@FETCH_STATUS = 0
    BEGIN
        BEGIN TRY
            SET @sql = 'CREATE TABLE ' + QUOTENAME(@keyword) + ' (id INT)';
            EXEC(@sql);

            SET @sql = 'DROP TABLE ' + QUOTENAME(@keyword);
            EXEC(@sql);

            INSERT INTO keyword_test_result
            VALUES ('sqlserver', @keyword, 'TABLE', 'OK', NULL, GETDATE());
        END TRY
        BEGIN CATCH
            INSERT INTO keyword_test_result
            VALUES ('sqlserver', @keyword, 'TABLE', 'FAIL', ERROR_MESSAGE(), GETDATE());
        END CATCH;

        FETCH NEXT FROM cur INTO @keyword;
    END

    CLOSE cur;
    DEALLOCATE cur;
END;

3.3.3 存储过程(不加引号)

CREATE OR ALTER PROCEDURE p_mssql_raw_keyword
AS
BEGIN
    SET NOCOUNT ON;

    DECLARE @keyword NVARCHAR(100);
    DECLARE @sql NVARCHAR(MAX);

    DECLARE cur CURSOR FOR
        SELECT word FROM keyword_list;

    OPEN cur;
    FETCH NEXT FROM cur INTO @keyword;

    WHILE @@FETCH_STATUS = 0
    BEGIN

        /* ================= TABLE ================= */
        BEGIN TRY
            SET @sql = N'CREATE TABLE ' + @keyword + N' (id INT)';
            EXEC sp_executesql @sql;

            SET @sql = N'DROP TABLE ' + @keyword;
            EXEC sp_executesql @sql;

            INSERT INTO keyword_test_result
            VALUES ('mssql_raw', @keyword, 'TABLE', 'OK', NULL, GETDATE());
        END TRY
        BEGIN CATCH
            INSERT INTO keyword_test_result
            VALUES ('mssql_raw', @keyword, 'TABLE', 'FAIL', ERROR_MESSAGE(), GETDATE());
        END CATCH;

        /* ================= COLUMN ================= */
        BEGIN TRY
            SET @sql = N'CREATE TABLE t_tmp (' + @keyword + N' INT)';
            EXEC sp_executesql @sql;

            DROP TABLE t_tmp;

            INSERT INTO keyword_test_result
            VALUES ('mssql_raw', @keyword, 'COLUMN', 'OK', NULL, GETDATE());
        END TRY
        BEGIN CATCH
            INSERT INTO keyword_test_result
            VALUES ('mssql_raw', @keyword, 'COLUMN', 'FAIL', ERROR_MESSAGE(), GETDATE());
        END CATCH;

        /* ================= FUNCTION ================= */
        BEGIN TRY
            SET @sql =
                N'CREATE FUNCTION ' + @keyword + N'(@x INT) RETURNS INT AS BEGIN RETURN @x END';

            EXEC sp_executesql @sql;

            SET @sql = N'DROP FUNCTION ' + @keyword;
            EXEC sp_executesql @sql;

            INSERT INTO keyword_test_result
            VALUES ('mssql_raw', @keyword, 'FUNCTION', 'OK', NULL, GETDATE());
        END TRY
        BEGIN CATCH
            INSERT INTO keyword_test_result
            VALUES ('mssql_raw', @keyword, 'FUNCTION', 'FAIL', ERROR_MESSAGE(), GETDATE());
        END CATCH;

        FETCH NEXT FROM cur INTO @keyword;
    END

    CLOSE cur;
    DEALLOCATE cur;
END;

3.3.4 执行结果

3.4 Oracle

3.4.1 关键字来源

image.png

3.4.2 存储过程(不加引号)

CREATE OR REPLACE PROCEDURE p_oracle_keyword IS
  CURSOR c_keywords IS
    SELECT keyword FROM v$reserved_words;

  v_sql    VARCHAR2(4000);
  v_errmsg VARCHAR2(4000);
BEGIN

  FOR r IN c_keywords LOOP

    BEGIN
      v_sql := 'CREATE TABLE ' || r.keyword || ' (id NUMBER)';
      EXECUTE IMMEDIATE v_sql;

      EXECUTE IMMEDIATE 'DROP TABLE ' || r.keyword;

      INSERT INTO keyword_test_result
      VALUES ('oracle', r.keyword, 'TABLE', 'OK', NULL, SYSDATE);

    EXCEPTION
      WHEN OTHERS THEN
        v_errmsg := SQLERRM;

        INSERT INTO keyword_test_result
        VALUES ('oracle', r.keyword, 'TABLE', 'FAIL', v_errmsg, SYSDATE);
    END;

    BEGIN
      v_sql := 'CREATE TABLE t_test ( ' || r.keyword || ' NUMBER )';
      EXECUTE IMMEDIATE v_sql;

      EXECUTE IMMEDIATE 'DROP TABLE t_test';

      INSERT INTO keyword_test_result
      VALUES ('oracle', r.keyword, 'COLUMN', 'OK', NULL, SYSDATE);

    EXCEPTION
      WHEN OTHERS THEN
        v_errmsg := SQLERRM;

        INSERT INTO keyword_test_result
        VALUES ('oracle', r.keyword, 'COLUMN', 'FAIL', v_errmsg, SYSDATE);
    END;
    BEGIN
      v_sql := '
        CREATE OR REPLACE FUNCTION ' || r.keyword || ' (x NUMBER)
        RETURN NUMBER
        IS
        BEGIN
          RETURN x;
        END;
      ';

      EXECUTE IMMEDIATE v_sql;

      EXECUTE IMMEDIATE 'DROP FUNCTION ' || r.keyword;

      INSERT INTO keyword_test_result
      VALUES ('oracle', r.keyword, 'FUNCTION', 'OK', NULL, SYSDATE);

    EXCEPTION
      WHEN OTHERS THEN
        v_errmsg := SQLERRM;

        INSERT INTO keyword_test_result
        VALUES ('oracle', r.keyword, 'FUNCTION', 'FAIL', v_errmsg, SYSDATE);
    END;

  END LOOP;

  COMMIT;
END;
/



3.4.3 执行结果

image.png
不加引号的结果
image.png
不支持的关键词如下:
Oracle_字段名不支持的关键词.xlsx
Oracle_表名不支持的关键词.xlsx

3.5 DM数据库

3.5.1 关键字来源



SQL> select count(*) from SYS.V$RESERVED_WORDS;

LINEID     COUNT(*)
---------- --------------------
1          864


3.5.2 存储过程不加引号

  CURSOR c_keywords IS
    SELECT keyword FROM v$reserved_words;

  v_sql    VARCHAR2(4000);
  v_errmsg VARCHAR2(4000);
BEGIN

  FOR r IN c_keywords LOOP
    BEGIN
      v_sql := 'CREATE TABLE ' || r.keyword || ' (id NUMBER)';
      EXECUTE IMMEDIATE v_sql;

      EXECUTE IMMEDIATE 'DROP TABLE ' || r.keyword;

      INSERT INTO keyword_test_result
      VALUES ('dm', r.keyword, 'TABLE', 'OK', NULL, SYSDATE);

    EXCEPTION
      WHEN OTHERS THEN
        v_errmsg := SQLERRM;

        INSERT INTO keyword_test_result
        VALUES ('dm', r.keyword, 'TABLE', 'FAIL', v_errmsg, SYSDATE);
    END;

    BEGIN
      v_sql := 'CREATE TABLE t_test ( ' || r.keyword || ' NUMBER )';
      EXECUTE IMMEDIATE v_sql;

      EXECUTE IMMEDIATE 'DROP TABLE t_test';

      INSERT INTO keyword_test_result
      VALUES ('dm', r.keyword, 'COLUMN', 'OK', NULL, SYSDATE);

    EXCEPTION
      WHEN OTHERS THEN
        v_errmsg := SQLERRM;

        INSERT INTO keyword_test_result
        VALUES ('dm', r.keyword, 'COLUMN', 'FAIL', v_errmsg, SYSDATE);
    END;

    BEGIN
      v_sql := '
        CREATE OR REPLACE FUNCTION ' || r.keyword || ' (x NUMBER)
        RETURN NUMBER
        IS
        BEGIN
          RETURN x;
        END;
      ';

      EXECUTE IMMEDIATE v_sql;

      EXECUTE IMMEDIATE 'DROP FUNCTION ' || r.keyword;

      INSERT INTO keyword_test_result
      VALUES ('dm', r.keyword, 'FUNCTION', 'OK', NULL, SYSDATE);

    EXCEPTION
      WHEN OTHERS THEN
        v_errmsg := SQLERRM;

        INSERT INTO keyword_test_result
        VALUES ('dm', r.keyword, 'FUNCTION', 'FAIL', v_errmsg, SYSDATE);
    END;

  END LOOP;

  COMMIT;
END;

3.5.3 执行结果


SQL> select db_type,test_type,result,count(*) from keyword_test_result group by db_type,test_type,result;

LINEID     DB_TYPE TEST_TYPE RESULT COUNT(*)
---------- ------- --------- ------ --------------------
1          dm      TABLE     FAIL   239
2          dm      COLUMN    FAIL   202
3          dm      FUNCTION  FAIL   239
4          dm      TABLE     OK     625
5          dm      COLUMN    OK     662
6          dm      FUNCTION  OK     625

6 rows got


达梦数据库不加引号,关键不支持函数、表、字段名成的如下:
达梦函数不加引号失败关键字详情.xlsx
达梦表名不加引号关键字失败详情.xlsx
DM字段不加引号关键词创建失败.xlsx

4.测试结果统计

4.1 添加引号的结果

image.png

4.2 不加引号的测试结果

image.png

4.3 重点对比说明DM和Oracle对比

对比说明:以下关键字同时存在于达梦(DM)与 Oracle 的保留字清单中,在未使用双引号("")强制转义的原生命名场景

  • 达梦(DM):禁止直接用作表名、字段名等对象标识;
  • Oracle:允许直接用作表名、字段名等对象标识。

image.png
image.png
image.png
image.png
image.png

5. 核心对比分析

5.1 不加引号

在不使用转义的情况下,各数据库对关键字限制差异明显:

  • DM: 限制最严格,大部分保留关键字无法作为表名或字段名使用
  • Oracle:限制较为严格,大部分保留关键字无法作为表名或字段名使用
  • PostgreSQL:对标准SQL关键字限制较严格,但部分关键字仍可使用
  • SQL Server:与PostgreSQL类似,部分关键字需避免直接使用
  • MySQL:相对宽松,部分关键字在特定上下文下仍可使用
    整体表现为:Oracle > PostgreSQL ≈ SQL Server > MySQL(严格程度)

5.2 加引号情况下

在使用转义符后,四类数据库均显著放宽限制:

  • DM/Oracle / PostgreSQL/MySQL:使用双引号后,绝大可作为对象名使用
  • SQL Server:使用方括号后基本不受限制
    但需要注意:
    加引号后对象名称区分大小写,且使用时必须保持一致,否则易导致SQL执行异常。

5.3 函数名限制(单独拎出来)

在函数名使用方面,各数据库限制更为严格

  • DM : 关键字部分可用,但仍建议避免
  • Oracle:关键字基本无法直接作为函数名使用(需强制转义)
  • PostgreSQL:部分关键字可使用,但存在语法冲突风险
  • MySQL:相对宽松,但仍建议避免
  • SQL Server:建议统一规避关键字命名函数
    整体建议:函数命名应避免使用任何关键字。

#6 工程化使用Python 模拟客户端调用驱动来访问数据库

6.1 依赖

pip install oracledb pymysql psycopg2-binary pyodbc pandas

单独部署达梦的dmPython依赖包

6.2 统一结果表

CREATE TABLE keyword_test_result (
    db_type        VARCHAR(20),
    keyword        VARCHAR(100),
    test_type      VARCHAR(20),
    quoted         VARCHAR(5),
    success        VARCHAR(5),
    error_msg      VARCHAR(4000),
    test_time      TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

6.3 通用Python 脚本

import pandas as pd
import traceback

CONFIG = {
    "oracle": {
        "user": "xxx",
        "password": "xxx",
        "dsn": "ip:port/service"
    },
    "mysql": {
        "host": "ip",
        "user": "xxx",
        "password": "xxx",
        "database": "test"
    },
    "postgres": {
        "host": "ip",
        "user": "xxx",
        "password": "xxx",
        "dbname": "test"
    },
    "sqlserver": {
        "conn_str": "DRIVER={ODBC Driver 17 for SQL Server};SERVER=ip;DATABASE=test;UID=xxx;PWD=xxx"
    }
}

def safe_exec(cursor, sql):
    try:
        cursor.execute(sql)
        return "yes", ""
    except Exception as e:
        return "no", str(e)

# ========= DM ============
def test_DM():
    import dmPython
    conn = oracledb.connect(**CONFIG["oracle"])
    cur = conn.cursor()

    cur.execute("SELECT keyword FROM v$reserved_words")
    keywords = [r[0] for r in cur.fetchall()]

    results = []

    for kw in keywords:
        # table
        for quoted in [False, True]:
            name = f'"{kw}"' if quoted else kw

            sql = f"CREATE TABLE {name} (id NUMBER)"
            ok, err = safe_exec(cur, sql)

            if ok == "yes":
                cur.execute(f"DROP TABLE {name}")

            results.append(("dm", kw, "table", str(quoted), ok, err))

        # column
        for quoted in [False, True]:
            col = f'"{kw}"' if quoted else kw

            sql = f"CREATE TABLE t_tmp ({col} NUMBER)"
            ok, err = safe_exec(cur, sql)

            if ok == "yes":
                cur.execute("DROP TABLE t_tmp")

            results.append(("dm", kw, "column", str(quoted), ok, err))

    return results

# ========= Oracle =========
def test_oracle():
    import oracledb
    conn = oracledb.connect(**CONFIG["oracle"])
    cur = conn.cursor()

    cur.execute("SELECT keyword FROM v$reserved_words")
    keywords = [r[0] for r in cur.fetchall()]

    results = []

    for kw in keywords:
        # table
        for quoted in [False, True]:
            name = f'"{kw}"' if quoted else kw

            sql = f"CREATE TABLE {name} (id NUMBER)"
            ok, err = safe_exec(cur, sql)

            if ok == "yes":
                cur.execute(f"DROP TABLE {name}")

            results.append(("oracle", kw, "table", str(quoted), ok, err))

        # column
        for quoted in [False, True]:
            col = f'"{kw}"' if quoted else kw

            sql = f"CREATE TABLE t_tmp ({col} NUMBER)"
            ok, err = safe_exec(cur, sql)

            if ok == "yes":
                cur.execute("DROP TABLE t_tmp")

            results.append(("oracle", kw, "column", str(quoted), ok, err))

    return results


# ========= MySQL =========
def test_mysql():
    import pymysql
    conn = pymysql.connect(**CONFIG["mysql"])
    cur = conn.cursor()

    cur.execute("SELECT WORD FROM INFORMATION_SCHEMA.KEYWORDS")
    keywords = [r[0] for r in cur.fetchall()]

    results = []

    for kw in keywords:
        for quoted in [False, True]:
            name = f"`{kw}`" if quoted else kw

            sql = f"CREATE TABLE {name} (id INT)"
            ok, err = safe_exec(cur, sql)

            if ok == "yes":
                cur.execute(f"DROP TABLE {name}")

            results.append(("mysql", kw, "table", str(quoted), ok, err))

    return results


# ========= PostgreSQL =========
def test_pg():
    import psycopg2
    conn = psycopg2.connect(**CONFIG["postgres"])
    cur = conn.cursor()

    cur.execute("SELECT word FROM pg_get_keywords()")
    keywords = [r[0] for r in cur.fetchall()]

    results = []

    for kw in keywords:
        for quoted in [False, True]:
            name = f'"{kw}"' if quoted else kw

            sql = f"CREATE TABLE {name} (id INT)"
            ok, err = safe_exec(cur, sql)

            if ok == "yes":
                cur.execute(f"DROP TABLE {name}")

            results.append(("postgres", kw, "table", str(quoted), ok, err))

    return results


# ========= SQL Server =========
def test_sqlserver():
    import pyodbc
    conn = pyodbc.connect(CONFIG["sqlserver"]["conn_str"])
    cur = conn.cursor()

    cur.execute("SELECT keyword FROM keyword_source")
    keywords = [r[0] for r in cur.fetchall()]

    results = []

    for kw in keywords:
        for quoted in [False, True]:
            name = f"[{kw}]" if quoted else kw

            sql = f"CREATE TABLE {name} (id INT)"
            ok, err = safe_exec(cur, sql)

            if ok == "yes":
                cur.execute(f"DROP TABLE {name}")

            results.append(("sqlserver", kw, "table", str(quoted), ok, err))

    return results

def main():
    all_results = []

    all_results += test_oracle()
    all_results += test_mysql()
    all_results += test_pg()
    # all_results += test_sqlserver()

    df = pd.DataFrame(all_results, columns=[
        "db_type", "keyword", "test_type", "quoted", "success", "error_msg"
    ])

    df.to_csv("keyword_test_result.csv", index=False)
    print("importer CSV")


if __name__ == "__main__":
    main()

7.结论

  1. 不使用转义的情况下,关键字作为对象名存在较高风险,不同数据库兼容性较差。
  2. 使用转义符可在一定程度上规避限制,但会引入大小写敏感及使用复杂度问题,不建议作为通用方案。
  3. 函数命名对关键字最为敏感,建议统一规避。
  4. 在多数据库或迁移场景中,应建立统一命名规范,避免使用关键字作为表名、字段名或函数名。
评论
后发表回复

作者

文章

阅读量

获赞

扫一扫
联系客服