暂无图片
暂无图片
2
暂无图片
暂无图片
暂无图片

金仓兼容SQL Server 深度体验

原创 董小姐 2025-07-07
571

兼容性说明

KingbaseES对SQL Server的兼容性已达到较高水平,常用功能兼容性超过90%,能够满足大多数业务场景的无缝迁移需求。其兼容性不仅体现在基础功能覆盖上,更通过深度适配SQL Server特有语法和功能,实现了迁移过程中的低风险、低成本和低难度。

兼容性特性

  1. 数据类型兼容
  • 支持SQL Server中常用的整数、浮点数、日期时间、字符串等基础数据类型,并对特殊类型(如TIMESTAMP)实现完全业务功能通用。
  • 针对SQL Server的IDENTITY自增字段特性,KingbaseES支持IDENTITY函数和数据类型,并兼容自增字段的identity_insert属性,确保DML操作的无缝衔接。
  • 新增对SQL Server特有类型(如bitsql_variantsysname)的全面支持,用户可直接沿用原有类型定义和运算逻辑。
  1. SQL语法与子句兼容
  • 兼容SQL Server的TOP子句、多表联合DML语法(如UPDATE语句支持多表JOIN)、COMPUTE子句等特色功能。
  • 支持FULL JOININNER HASH JOIN等复杂连接语法,以及ORDER BY中的OPTION()语法,确保查询逻辑的完整迁移。
  • 对XML数据处理能力(如OPENXMLfor XML path(''))和JSON数据类型提供全面支持,满足非结构化数据存储需求。
  1. 存储过程与PL/SQL兼容
  • 开发了语句拆分算法,实现对SQL Server灵活PL/SQL语法功能的深度兼容,包括异常处理、游标操作、动态语句执行等。
  • 支持存储过程的RETURN返回值功能和函数返回表数据类型,兼容触发器全种类(如AFTERINSTEAD OF)和事务控制语句(如SAVEPOINT)。
  • 对SQL Server中的系统变量(如ROWCOUNTTRANCOUNT)和函数(如IDENTITY()ISNUMERIC())实现全面兼容,确保应用逻辑无需修改即可迁移。
  1. 临时表与事务兼容
  • 兼容SQL Server的全局临时表(##temp)和本地临时表(#temp)使用方式,支持跨会话的临时表访问。
  • 提供强事务处理能力,支持ACID特性,并兼容SQL Server的事务隔离级别和保存点(SAVEPOINT)机制。

下载并安装SQL Server 兼容版KES数据库

下载SQL Server 兼容版数据库

下载地址:https://www.kingbase.com.cn/download.html

务必在下拉框中选择含SQL Server 兼容版的版本,根据操作系统和CPU类型下载对应的安装介质,安装介质较V8R6大一些,有2.5G大小。

下载后上传到/opt目录下。

下载授权文件

KingbaseES数据库(SQLServer兼容版)授权文件时长限制为90天,以数据库首次启动为首日开始计算。

该版本授权文件下载后直接上传可用,不用像V8R6版本的授权文件需要解压才能用,省却了解压步骤,更方便省时。

下载后上传到/opt目录下。

安装SQL Server 兼容版数据库

安装过程和V8R6一样,安装过程省略,过程中注意数据库模式为SQL Server。

安装完成后登录数据库查看数据库兼容模式,输出如下:

test=# show database_mode;
 database_mode
---------------
 sqlserver
(1 row)

兼容测试SQL Server特殊数据类型与对象

ROWVERSION数据类型

含义

ROWVERSION(也称为 TIMESTAMP)是SQL Server 兼容版KES数据库中的一种特殊数据类型,它会自动生成一个唯一的二进制数字,每次修改或插入包含 ROWVERSION 列的行时都会更新。

ROWVERSION 特性:

  1. 自动更新的二进制数字(8字节)
  2. 每个数据库唯一
  3. 不能手动指定值
  4. 常用于检测行是否被修改

语法:

 ROWVERSION 

值域: 该类型存储大小为 8 个字节。接受 NULL 输入,固定以 0x**************** 的 8 字节的 16 进制格式输出。

注意:

  1. ROWVERSION 值仅在表内唯一,不在数据库内唯一
  2. 不能将 NULL 值插入 ROWVERSION 列
  3. 每个表只能有一个 ROWVERSION 列
  4. ROWVERSION 不表示实际时间或日期
  5. 在 SQL Server 2016 及更高版本中,TIMESTAMP 是 ROWVERSION 的同义词
  6. 当插入或更新行时,Version列会自动更新。
  7. ROWVERSION 不适合作为业务主键,仅用于技术性版本跟踪。

实操

创建表

--创建表
CREATE TABLE RowVersionTest (
    ID INT PRIMARY KEY,
    Data VARCHAR(100),
    RowVer ROWVERSION
);

插入数据

-- 插入数据
INSERT INTO RowVersionTest (ID, Data) VALUES (1, 'Initial Data');
INSERT INTO RowVersionTest (ID, Data) VALUES (2, 'Another Record');

-- 查看结果
SELECT ID, Data, RowVer FROM RowVersionTest;

输出如下:
 ID |      Data      |       RowVer
----+----------------+--------------------
  1 | Initial Data   | 0x0000000000000001
  2 | Another Record | 0x0000000000000002
(2 rows)

更新数据测试

-- 更新数据
UPDATE RowVersionTest SET Data = 'Updated Data' WHERE ID = 1;

-- 更新后查看值
SELECT RowVer FROM RowVersionTest WHERE ID = 1;
       RowVer
--------------------
 0x0000000000000003
(1 row)

会发现有以下特点:

  • 每行更新时自动生成新的 8 字节二进制值。
  • 值全局递增(数据库内唯一)。
  • 用于乐观并发控制(检查修改冲突)。

问题处理

ERROR: test or kingbase database not support use rowversion type and correlative functions.
问题描述

插入数据时提示如下报错:ERROR: test or kingbase database not support use rowversion type and correlative functions.

test=# INSERT INTO RowVersionTest (ID, Data) VALUES (2, 'Another Record');
ERROR:  test or kingbase database not support use rowversion type and correlative functions.
解决办法

SQL Server模式不能在test库去执行创建语句,可以去master或者自建模拟库进行操作。

--创建业务库
master=# create database sqlserver;
CREATE DATABASE
master=# \c sqlserver
You are now connected to database "sqlserver" as userName "system".
sqlserver=# CREATE TABLE RowVersionTest (
sqlserver(#     ID INT PRIMARY KEY,
sqlserver(#     Data VARCHAR(100),
sqlserver(#     RowVer ROWVERSION
sqlserver(# );
CREATE TABLE
sqlserver=# INSERT INTO RowVersionTest (ID, Data) VALUES (1, 'Initial Data');
INSERT 0 1
sqlserver=# INSERT INTO RowVersionTest (ID, Data) VALUES (2, 'Another Record');
INSERT 0 1
sqlserver=# SELECT ID, Data, RowVer FROM RowVersionTest;
 ID |      Data      |       RowVer
----+----------------+--------------------
  1 | Initial Data   | 0x0000000000000001
  2 | Another Record | 0x0000000000000002
(2 rows)

执行正常,说明SQL Server 兼容模式下的sql兼容性很高,原模原样sql拿来即用,省时省力。

SQL_VARIANT数据类型

含义

sql_variant 数据类型用于存储支持的各种数据类型。

语法:

SQL_VARIANT

使用说明 :

1. sql_variant 数据类型支持作为表列,变量,函数参数和返回值使用。

2. 基础数据类型,都可以隐式转换为 sql_variant 类型,但不支持 sql_variant 类型隐式转换为其它类型。

3. sql_variant 数据类型必须先转换为基本数据类型值,然后才能参与算数运算

4. sql_variant 数据支持导入导出。导出时如果指定--copy-binary 参数,能够导出属性,导入后数据的属性信息不变。如果不指定--copy-binary 参数时,导出仅备份数据,不导出属性信息,导入时数据的基础类型全部是 varchar 类型。

实操

创建测试表

-- 创建包含 sql_variant 列的测试表
CREATE TABLE VariantTest (
    ID INT IDENTITY(1,1) PRIMARY KEY,
    VariantValue sql_variant,
    Description NVARCHAR(100)
);

插入测试数据

-- 插入不同类型的数据到 sql_variant 列
INSERT INTO VariantTest (VariantValue, Description)
VALUES 
    (42, '整数'),
    (3.14159, '浮点数'),
    ('Hello World', '字符串'),
    (CAST('2023-01-15' AS DATE), '日期'),
    (CAST('12:34:56' AS TIME), '时间'),
    (1, '布尔值(实际存储为整数)'),
    (NULL, 'NULL值');

查询数据

基本查询
-- 基本查询
SELECT ID, VariantValue, Description FROM VariantTest;

输出如下:
sqlserver=# SELECT ID, VariantValue, Description FROM VariantTest;
 ID |   VariantValue   |      Description
----+------------------+------------------------
  1 | 42               | 整数
  2 | 3.14159          | 浮点数
  3 | Hello World      | 字符串
  4 | 2023-01-15       | 日期
  5 | 12:34:56.0000000 | 时间
  6 | 1                | 布尔值(实际存储为整数)
  7 |                  | NULL值
(7 rows)
使用 SQL_VARIANT_PROPERTY 获取值的属性
-- 使用 SQL_VARIANT_PROPERTY 获取值的属性
SELECT 
    ID,
    VariantValue,
    Description,
    SQL_VARIANT_PROPERTY(VariantValue, 'BaseType') AS BaseType,
    SQL_VARIANT_PROPERTY(VariantValue, 'Precision') AS Precision,
    SQL_VARIANT_PROPERTY(VariantValue, 'Scale') AS Scale,
    SQL_VARIANT_PROPERTY(VariantValue, 'TotalBytes') AS TotalBytes,
    SQL_VARIANT_PROPERTY(VariantValue, 'Collation') AS Collation,
    SQL_VARIANT_PROPERTY(VariantValue, 'MaxLength') AS MaxLength
FROM VariantTest;

输出如下:

 ID |   VariantValue   |      Description       | BaseType | Precision | Scale | TotalBytes | Collation | MaxLength
----+------------------+------------------------+----------+-----------+-------+------------+-----------+-----------
  1 | 42               | 整数                   | int      | 10        | 0     | 10         |           | 4
  2 | 3.14159          | 浮点数                 | numeric  | 6         | 5     | 20         |           | 14
  3 | Hello World      | 字符串                 | varchar  | 0         | 0     | 19         | ci_x_icu  | 11
  4 | 2023-01-15       | 日期                   | date     | 10        | 0     | 10         |           | 4
  5 | 12:34:56.0000000 | 时间                   | time     | 8         | 0     | 14         |           | 8
  6 | 1                | 布尔值(实际存储为整数) | int      | 10        | 0     | 10         |           | 4
  7 |                  | NULL值                 |          |           |       |            |           |
(7 rows)

类型转换测试

-- 将 sql_variant 转换为特定类型
SELECT 
    ID,
    VariantValue,
    Description,
    CAST(VariantValue AS INT) AS AsInt,
    CAST(VariantValue AS FLOAT) AS AsFloat,
    CAST(VariantValue AS NVARCHAR(50)) AS AsString,
    CAST(VariantValue AS DATE) AS AsDate
FROM VariantTest
WHERE SQL_VARIANT_PROPERTY(VariantValue, 'BaseType') IN ('int', 'float', 'nvarchar', 'date');
问题处理:ERROR: cannot to find cast from source type "int"to target type "date"
  • 问题描述:

执行以上SQL输出ERROR: cannot to find cast from source type "int"to target type "date"

  • 解决办法

sql_variant 数据类型必须先转换为基本数据类型值,然后才能参与算数运算

类型转换不对 int 转不来 date格式,在SQL Server兼容金仓库中执行需转换成以下写法,直接执行会报错:ERROR: cannot to find cast from source type "int"to target type "date"

SELECT 
    ID,
    VariantValue,
    Description,
    -- 转换为整数
    CASE WHEN pg_typeof(VariantValue)::text IN ('integer', 'bigint', 'smallint') 
         THEN VariantValue::int 
         ELSE NULL END AS AsInt,
    
    -- 转换为浮点数
    CASE WHEN pg_typeof(VariantValue)::text IN ('real', 'double precision') 
         THEN VariantValue::float 
         ELSE NULL END AS AsFloat,
    
    -- 转换为文本
    VariantValue::text AS AsString,
    
    -- 转换为日期(安全处理)
    CASE 
        WHEN pg_typeof(VariantValue)::text = 'date' 
            THEN VariantValue::date
        WHEN pg_typeof(VariantValue)::text IN ('integer', 'bigint') 
            THEN to_date(VariantValue::text, 'YYYYMMDD') 
        ELSE NULL 
    END AS AsDate
FROM VariantTest
WHERE pg_typeof(VariantValue)::text IN ('integer', 'bigint', 'smallint', 
                                       'real', 'double precision', 
                                       'text', 'varchar', 'date');

比较操作测试

SQLServer原生写法:

-- 比较操作(注意类型必须兼容)
DECLARE @compareValue sql_variant = 42;

SELECT ID, VariantValue, Description
FROM VariantTest
WHERE VariantValue = @compareValue;

-- 字符串比较
DECLARE @strCompare sql_variant = 'Hello World';

SELECT ID, VariantValue, Description
FROM VariantTest
WHERE VariantValue = @strCompare;

在SQL Server兼容金仓库中执行需转换成以下写法,直接执行会报错:ERROR: Must declare user variable "@compareValue" before use it.

-- 比较操作(注意类型必须兼容)
\set SQLTERM /
begin
declare @compareValue sql_variant ;
set @compareValue = 42 ;
SELECT ID, VariantValue, Description FROM VariantTest WHERE VariantValue = @compareValue; 
end;
/

-- 字符串比较
\set SQLTERM /
begin
DECLARE @strCompare sql_variant ;
set  @strCompare='Hello World';
SELECT ID, VariantValue, Description
FROM VariantTest
WHERE VariantValue = @strCompare;
end;
/
问题处理:ERROR: Must declare user variable "@compareValue" before use it.
  • 问题描述:在进行比较操作时提示如下报错:ERROR: Must declare user variable "@compareValue" before use it.
sqlserver=# DECLARE @compareValue sql_variant = 42;
sqlserver=# SELECT ID, VariantValue, Description
sqlserver-# FROM VariantTest
sqlserver-# WHERE VariantValue = @compareValue;
ERROR:  Must declare user variable "@compareValue" before use it.
  • 解决办法:

在SQL Server兼容金仓库中执行需要转换成以下写法,即在一个PL/SQL块中。

\set SQLTERM /
begin
declare @compareValue sql_variant ;
set @compareValue = 42 ;
SELECT ID, VariantValue, Description FROM VariantTest WHERE VariantValue = @compareValue; 
end;

输出如下:
 ID | VariantValue | Description
----+--------------+-------------
  1 | 42           | 整数
(1 row)

注意事项测试

-- 尝试插入不支持的类型(会失败)
BEGIN TRY
    INSERT INTO VariantTest (VariantValue, Description)
    VALUES (CAST('不支持的类型' AS TEXT), '这会失败');
END TRY
BEGIN CATCH
    PRINT '错误: ' + ERROR_MESSAGE();
END CATCH

-- 排序行为(按基础类型排序)
SELECT ID, VariantValue, Description
FROM VariantTest
ORDER BY VariantValue;

在SQL Server兼容金仓库中执行需要转换成以下写法,即在一个PL/SQL块中。

-- 尝试插入不支持的类型(会失败)
\set SQLTERM /
BEGIN TRY
    INSERT INTO VariantTest (VariantValue, Description)
    VALUES (CAST('不支持的类型' AS TEXT), '这会失败');
END TRY
BEGIN CATCH
    PRINT '错误: ' + ERROR_MESSAGE();
END CATCH;
/

-- 排序行为(按基础类型排序)
SELECT ID, VariantValue, Description
FROM VariantTest
ORDER BY VariantValue;
/

输出如下:

 ID |   VariantValue   |      Description
----+------------------+------------------------
  7 |                  | NULL值
  3 | Hello World      | 字符串
  8 | 不支持的类型     | 这会失败
  6 | 1                | 布尔值(实际存储为整数)
  2 | 3.14159          | 浮点数
  1 | 42               | 整数
  5 | 12:34:56.0000000 | 时间
  4 | 2023-01-15       | 日期
(8 rows)

性能考虑

sql_variant 数据类型必须先转换为基本数据类型值,然后才能参与算数运算

-- 创建一个大表测试性能
DECLARE @i INT = 0;
BEGIN TRANSACTION;
WHILE @i < 10000
BEGIN
    INSERT INTO VariantTest (VariantValue, Description)
    VALUES 
        (CASE WHEN @i % 4 = 0 THEN CAST(@i AS INT)
              WHEN @i % 4 = 1 THEN CAST(@i AS FLOAT)
              WHEN @i % 4 = 2 THEN 'String ' + CAST(@i AS NVARCHAR(10))
              ELSE CAST(DATEADD(DAY, @i, '2000-01-01') AS DATE)
         END,
         'Value ' + CAST(@i AS NVARCHAR(10)));
    SET @i = @i + 1;
END
COMMIT TRANSACTION;

-- 查询性能测试(注意索引使用)
-- 通常不建议在 sql_variant 列上创建索引
SELECT COUNT(*) FROM VariantTest WHERE VariantValue = 5000;
问题处理

问题描述:执行以上PL/SQL块提示报错:ERROR: failed to find conversion function from int to date

PL/MSSQL function inline_code_block line 6 at SQL statement
ERROR:  failed to find conversion function from int to date
CONTEXT:  SQL statement "INSERT INTO VariantTest (VariantValue, Description)
    VALUES
        (CASE WHEN @i % 4 = 0 THEN CAST(@i AS INT)
              WHEN @i % 4 = 1 THEN CAST(@i AS FLOAT)
              WHEN @i % 4 = 2 THEN 'String ' + CAST(@i AS NVARCHAR(10))
              ELSE CAST(DATEADD(DAY, @i, '2000-01-01') AS DATE)
         END,
         'Value ' + CAST(@i AS NVARCHAR(10)))"

暂时还未找到解决办法,有解决办法的大佬可以文末留言,谢谢!

UNIQUEIDENTIFIER数据类型

含义

在SQL Server中,原生`UNIQUEIDENTIFIER`类型:

- 存储为16字节二进制值。

- 可以使用`NEWID()`函数生成随机GUID,或`NEWSEQUENTIALID()`生成顺序GUID(减少索引碎片)。

- 支持比较操作,但效率不如整数。

1. **尽可能使用原生`UNIQUEIDENTIFIER`**:除非有兼容性限制,否则直接使用原生类型。

2. **考虑使用`NEWSEQUENTIALID()`**:当GUID作为聚集索引键时,使用顺序GUID可以减少碎片。

3. **避免在频繁查询的列上使用GUID**:因为GUID较大且无序,可能导致索引碎片。如果必须使用,考虑非聚集索引。

原生 UNIQUEIDENTIFIER 的优势:

  • 真正的全局唯一性
  • 高效的存储(16字节)
  • 内置生成函数
  • 支持特殊函数如 NEWSEQUENTIALID()
  • 与 .NET Guid 结构兼容

实操

创建测试表

CREATE TABLE GuidTest (
    ID UNIQUEIDENTIFIER PRIMARY KEY DEFAULT NEWID(),
    Name NVARCHAR(50),
    CreatedDate DATETIME DEFAULT GETDATE(),
    RowVersion ROWVERSION
);

插入数据测试

方法1:使用 NEWID() 函数
INSERT INTO GuidTest (ID, Name) VALUES (NEWID(), 'Test Record 1');
方法2:使用默认值
INSERT INTO GuidTest (Name) VALUES ('Test Record 2');
方法3:显式指定 GUID 值
INSERT INTO GuidTest (ID, Name) 
VALUES ('12345678-1234-1234-1234-123456789ABC', 'Explicit GUID');

查询测试

-- 基本查询
SELECT * FROM GuidTest;

-- 按 GUID 查询
SELECT * FROM GuidTest WHERE ID = '12345678-1234-1234-1234-123456789ABC';

-- 转换函数测试
SELECT 
    ID,
    CAST(ID AS NVARCHAR(36)) AS GuidAsString,
    CONVERT(NVARCHAR(36), ID) AS GuidConverted,
    ID AS OriginalGuid
FROM GuidTest;

性能测试

索引效率测试
-- 插入大量数据
\set SQLTERM /
DECLARE @i INT = 0;
WHILE @i < 10000
BEGIN
    INSERT INTO GuidTest (Name) VALUES ('Record ' + CAST(@i AS NVARCHAR(10)));
    SET @i = @i + 1;
END
 
-- 测试查找性能
SET STATISTICS IO ON;
SET STATISTICS TIME ON;
 
-- 使用 GUID 查找
SELECT * FROM GuidTest WHERE ID = '12345678-1234-1234-1234-123456789ABC';
 
-- 使用聚集索引查找(如果表有聚集索引)
-- 对于 UNIQUEIDENTIFIER 主键,SQL Server 默认使用聚集索引

问题处理:ERROR: syntax error at or near "STATISTICS"

sqlserver=# SET STATISTICS IO ON;
sqlserver-# SET STATISTICS TIME ON;
sqlserver-# /
ERROR:  syntax error at or near "STATISTICS"
LINE 1: SET STATISTICS IO ON;

我当前知晓的是金仓库需要通过安装加载pg_stat_statements插件、配置pg_stat_statements采样参数、创建pg_stat_statements extension方可分析耗时IO的SQL。

与 INT 标识列比较
CREATE TABLE IntTest (
    ID INT IDENTITY(1,1) PRIMARY KEY,
    Name NVARCHAR(50)
);
 
-- 插入相同数量的数据
\set SQLTERM /
SET @i = 0;
WHILE @i < 10000
BEGIN
    INSERT INTO IntTest (Name) VALUES ('Record ' + CAST(@i AS NVARCHAR(10)));
    SET @i = @i + 1;
END
 
-- 比较查找性能
SELECT * FROM IntTest WHERE ID = 5000;

问题处理:ERROR: Must declare user variable "@i" before use it.

-- 插入相同数量的数据
\set SQLTERM /
SET @i = 0;
WHILE @i < 10000
BEGIN
    INSERT INTO IntTest (Name) VALUES ('Record ' + CAST(@i AS NVARCHAR(10)));
    SET @i = @i + 1;
END
执行提示如下报错:
ERROR:  Must declare user variable "@i" before use it.
CONTEXT:  SQL statement "SET @i = 0"
PL/MSSQL function inline_code_block line 2 at SET
ERROR:  Must declare user variable "@i" before use it.
CONTEXT:  SQL statement "SELECT @i < 10000"
PL/MSSQL function inline_code_block line 3 at WHILE

在SQL Server兼容金仓库中执行需要转换成以下写法:

\set SQLTERM /
DECLARE @i INT = 0;
WHILE @i < 10000
BEGIN
    INSERT INTO IntTest (Name) VALUES ('Record ' + CAST(@i AS NVARCHAR(10)));
    SET @i = @i + 1;
END
/

特殊函数测试

-- NEWSEQUENTIALID() 测试(只能在 DEFAULT 约束中使用)
CREATE TABLE SequentialGuidTest (
    ID UNIQUEIDENTIFIER PRIMARY KEY DEFAULT NEWSEQUENTIALID(),
    Name NVARCHAR(50)
);
 
INSERT INTO SequentialGuidTest (Name) VALUES ('Sequential 1'), ('Sequential 2');
SELECT * FROM SequentialGuidTest;
最佳实践测试
-- 测试组合主键
CREATE TABLE CompositeKeyTest (
    TenantID UNIQUEIDENTIFIER NOT NULL,
    EntityID UNIQUEIDENTIFIER NOT NULL,
    Name NVARCHAR(50),
    PRIMARY KEY (TenantID, EntityID)
);
 
-- 测试外键关系
CREATE TABLE RelatedTable (
    ID UNIQUEIDENTIFIER PRIMARY KEY DEFAULT NEWID(),
    ParentID UNIQUEIDENTIFIER,
    Description NVARCHAR(100),
    FOREIGN KEY (ParentID) REFERENCES GuidTest(ID)
);

测试结论

  1. 优点
  • 全局唯一性,适合分布式系统
  • NEWSEQUENTIALID() 可以减少页分裂
  • 安全性更高(不像自增ID那样暴露增长模式)
  1. 缺点
  • 存储空间比 INT/BIGINT 大
  • 随机性导致索引碎片化
  • 查询性能通常低于整数类型
  1. 适用场景
  • 合并来自不同系统的数据
  • 需要隐藏实际记录数的安全场景
  • 分布式数据库系统
  1. 不适用场景
  • 高吞吐量OLTP系统的主要键
  • 需要频繁范围查询的场景

SYSNAME数据类型

含义

在SQL Server中,sysname是一个系统数据类型,它用于存储对象(如表、列、存储过程等)的名称。实际上,sysname被定义为nvarchar(128),并且不允许为空(即NOT NULL)。但是,在系统表中,它有时也被定义为nvarchar(256),但根据官方文档,它通常是nvarchar(128)。

sysname 的本质:

  • 实际类型sysname 是系统定义的 nvarchar(128) 的别名。
  • 特性
  • 长度固定为 128 个 Unicode 字符(相当于 256 字节)。
  • 默认 不允许 NULL(除非显式指定)。
  • 用于存储数据库对象标识符(兼容 Unicode)。
  • 排序规则:默认使用数据库的排序规则

实操

创建测试表和数据

-- 创建测试表使用SYSNAME列
CREATE TABLE SysnameTest (
    ID INT IDENTITY(1,1) PRIMARY KEY,
    ObjectName SYSNAME NOT NULL,
    Description NVARCHAR(200)
);

-- 插入数据测试
INSERT INTO SysnameTest (ObjectName, Description)
VALUES ('Employees', 'Table containing employee data');

INSERT INTO SysnameTest (ObjectName, Description)
VALUES (N'产品表', 'Contains product information in Chinese');

-- 尝试插入超长名称(会失败,因为SYSNAME等同于nvarchar(128))
BEGIN TRY
    INSERT INTO SysnameTest (ObjectName, Description)
    VALUES (REPLICATE('A', 129), 'This will fail');
END TRY
BEGIN CATCH
    PRINT 'Error: ' + ERROR_MESSAGE();
END CATCH
会提示Error: value too long for type nvarchar(128)报错

变量声明测试

-- 声明SYSNAME变量
DECLARE @TableName SYSNAME = 'Customers';
DECLARE @ColumnName SYSNAME;

SET @ColumnName = 'LastName';

-- 使用变量构建动态SQL
DECLARE @SQL NVARCHAR(MAX);
SET @SQL = N'SELECT ' + QUOTENAME(@ColumnName) + ' FROM ' + QUOTENAME(@TableName);
PRINT @SQL;
-- 执行动态SQL
EXEC sp_executesql @SQL;

在SQL Server兼容金仓库中执行需要转换成以下写法,即在一个PL/SQL块中。

不然提示以下报错:ERROR: Must declare user variable "@ColumnName" before use it.

总结

整体上兼容度还是蛮高的,但是在系统sql、少量数据类型转换以及PL/SQL块上的兼容度还需要稍微手动更改下,相信在不久的将来会实现SQL Server 语句拿来即用。

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论