运行时名称:T-SQL;CLI
--dialect standard(默认),旧值mssql仍兼容;不需要插件。 先读 总览 了解方言隔离、事务模型和共享函数表。
1. 调用方式
dbsql --root /data sql mydb "SELECT TOP 5 id, name FROM users ORDER BY id"
T-SQL 是 CLI 的默认方言,可省略 --dialect。HTTP 侧 /api/sql、/api/select 的 "dialect" 留空或写 standard/mssql 都走这里。
2. 支持的语法
2.1 DDL
| 语句 | 说明 |
|---|---|
CREATE DATABASE <库> |
与方言无关的库级操作 |
CREATE TABLE <表> (<列> <类型> [约束], …, [表级约束]) |
见 2.2 / 2.3 |
DROP TABLE <表> |
— |
CREATE VIEW <视图> AS SELECT … / DROP VIEW <视图> |
不支持 CREATE OR REPLACE VIEW |
CREATE PROCEDURE <名> () AS BEGIN … END / DROP PROCEDURE <名> |
见 2.6 |
CREATE FUNCTION … / DROP FUNCTION … |
与过程同一套过程体解释器 |
CREATE TRIGGER … / DROP TRIGGER … |
见 2.7 |
CREATE INDEX <索引> ON <表> (<列>, …) |
不存在 CREATE UNIQUE INDEX |
ALTER TABLE <表> ADD <列定义> / MODIFY <列定义> / RENAME … |
一次只能一个子句,逗号分隔的多子句会被拒 |
SELECT … INTO <新表> FROM … |
建表并落数据;语句本身返回 0 行 |
2.2 类型映射
解析器把 SQL Server 常见类型名归一成引擎类型(crates/dbsql-sql/src/parser.rs 的 map_std_type):
| 写法 | 引擎类型 | 备注 |
|---|---|---|
NUMBER / NUMERIC / DECIMAL / DEC / MONEY / SMALLMONEY |
decimal |
DECIMAL(p,s) 会校验小数位;超位直接报错,不四舍五入 |
VARCHAR / NVARCHAR / VARCHAR2 / NVARCHAR2 / NTEXT / CLOB / NCLOB / TEXT / STRING / XML / SYSNAME |
string |
(n) 只解析、不校验长度 |
CHAR / NCHAR / CHAR2 |
char |
单字符类型,不是定长 n 字符串 |
DATE / TIMESTAMP / DATETIME / DATETIME2 / SMALLDATETIME |
datetime |
读回形如 2026-01-02 00:00:00 |
BOOLEAN / BOOL / BIT |
bool |
— |
INT / INTEGER / INT32 / INT64 |
int |
— |
BIGINT / LONG |
long |
— |
SMALLINT / INT16 |
short |
— |
TINYINT / BYTE |
byte |
注意 SQL Server 的 TINYINT 是 0–255 无符号,这里是有符号字节 |
REAL / FLOAT |
float |
单精度 |
DOUBLE / BINARY_DOUBLE |
double |
— |
GUID / UNIQUEIDENTIFIER |
guid |
— |
DATEONLY |
dateonly |
— |
JSON |
json |
写入时校验 JSON 语法 |
BLOB / BINARY / VARBINARY / IMAGE |
blob |
值用 0x… 十六进制字面量 |
引擎原生名(byte/bool/guid/string/int/long/datetime/dateonly/float/decimal/char/short/double/json/blob)也可直接写。
反直觉点:DDL 里的
FLOAT落单精度;但CONVERT(FLOAT, x)落双精度(与 SQL Server 的float(53)对齐)。要单精度请用REAL。
2.3 约束
- 列级:
PRIMARY KEY、NOT NULL、NULL、UNIQUE、CHECK (表达式)、DEFAULT <字面量>。 - 表级:
PRIMARY KEY (a, b)(复合)、UNIQUE (…)、CHECK (…)。 - 主键、
UNIQUE、CHECK都是真校验;复合主键冲突示例:错误:主键 (a, b) 冲突:列 (a, b) 的值 ('1', '1') 与表中已存在的行重复 CHECK示例:错误:检查约束 (v > 0) 未通过:表达式 \v > 0` 为假`
2.4 查询
SELECT:DISTINCT、表达式/别名、t.*、派生表、标量子查询、EXISTS/IN/BETWEEN/LIKE/IS NULL。JOIN:INNER/LEFT/RIGHT/FULL,ON任意布尔表达式。CROSS JOIN不支持。GROUP BY列/序号/表达式;HAVING;ORDER BY列/序号/表达式 +ASC/DESC+NULLS FIRST/NULLS LAST。- 分页三种写法都可用:
SELECT TOP 2 id FROM t ORDER BY id;
SELECT id FROM t ORDER BY id OFFSET 0 ROWS FETCH NEXT 2 ROWS ONLY;
SELECT id FROM t ORDER BY id LIMIT 2 OFFSET 0; -- 兼容写法
- 集合运算:
UNION/UNION ALL/INTERSECT/EXCEPT。连续链式只能同一种运算符,混用报连续集合运算只支持同一种运算符(UNION / UNION ALL / INTERSECT / EXCEPT);不同运算符请用 CTE 分组。 - CTE:
WITH x AS (…),递归需WITH r (n) AS (SELECT … UNION ALL SELECT … FROM r …)。 - 窗口:
ROW_NUMBER() OVER (ORDER BY …)可用;PARTITION BY报ROW_NUMBER 的 PARTITION BY 暂不支持。 UPDATE … SET … FROM 表 WHERE …可用(实测按FROM正确过滤)。INSERT … SELECT …可用。
2.5 字面量与标识符
| 写法 | 行为 |
|---|---|
'text' / N'中文' |
字符串字面量;N 前缀可用 |
[名字] |
标识符(方括号转义) |
"名字" |
字符串字面量,不是标识符:SELECT "id" FROM t 每行返回 id |
'a' + 'b' |
文本拼接(ab) |
CONVERT(INT, '12') |
支持;目标类型见 map_convert_type |
CAST(x AS 类型) |
支持 |
GETDATE() / SYSDATE / CURRENT_TIMESTAMP |
支持 |
2.6 存储过程与流程控制
CREATE PROCEDURE pc ()
AS
BEGIN
DECLARE @i INT;
DECLARE cur CURSOR FOR SELECT id FROM src;
OPEN cur;
FETCH NEXT FROM cur INTO @i;
CLOSE cur;
DEALLOCATE cur;
INSERT INTO t (id, v) VALUES (100, 'p');
END
- 过程名后必须带空参数括号:
CREATE PROCEDURE p () AS …;调用同样带括号:CALL p()。 - 过程体支持:
DECLARE、SET、SELECT @变量 = …、IF/ELSEIF/ELSE/END IF、WHILE/END、RETURN、游标(DECLARE CURSOR/OPEN/FETCH NEXT/CLOSE/DEALLOCATE)、EXEC '<动态 SQL>'、EXEC <过程>、INSERT … EXEC、PRINT(求值但不输出)。 - 会话级临时表
#t可在过程体内使用。 - 顶层
EXEC p不支持:错误:不支持的 SQL 语句类型:EXEC;顶层调用请用CALL p()。
2.7 触发器
CREATE TRIGGER trg_bi BEFORE INSERT ON t
AS RAISE '不允许插入';
CREATE TRIGGER trg_ai AFTER INSERT ON t
AS INSERT INTO audit (v) VALUES (NEW.v);
-- 可跟多条语句:INSERT …; INSERT …;
DROP TRIGGER trg_ai;
- 语法固定为
CREATE TRIGGER <名> BEFORE|AFTER INSERT|UPDATE|DELETE ON <表> AS <语句>[; <语句>]。 - 伪行:
NEW.col/OLD.col;RAISE '消息'中断并回滚。 - 体语句只允许
INSERT/UPDATE/DELETE/RAISE,不接受BEGIN … END。 - 触发器按语句触发;多语句体按顺序执行(实测一次插入写入了预期行数)。
2.8 SET 选项
只有下列选项会被接受;除 IDENTITY_INSERT 外都是校验后空操作:
SET NOCOUNT ON|OFF
SET ANSI_NULLS ON|OFF
SET ANSI_PADDING ON|OFF
SET ANSI_WARNINGS ON|OFF
SET ARITHABORT ON|OFF
SET CONCAT_NULL_YIELDS_NULL ON|OFF
SET NUMERIC_ROUNDABORT ON|OFF
SET IDENTITY_INSERT <表> ON|OFF -- 空操作
SET QUOTED_IDENTIFIER 明确拒绝:
错误:SET QUOTED_IDENTIFIER 暂不支持:本引擎不能按会话切换双引号的解释口径。请删掉这一行,脚本里的字符串统一用单引号
2.9 自增列
CREATE TABLE idt (id INT IDENTITY PRIMARY KEY, v VARCHAR(5));
INSERT INTO idt (v) VALUES ('a'); -- id 自动为 1
隐式列清单会剔除自增列;显式给自增列赋值会因列数/顺序不匹配报错。
2.10 事务
BEGIN [TRANSACTION] / COMMIT / ROLLBACK 只允许平台管理员;事务是进程级单事务,CLI 每条命令一个进程,见 总览第 7 节。
3. 不支持的功能
| 功能 | 实测报错 / 表现 | 替代 |
|---|---|---|
CROSS JOIN |
SELECT 语句末尾存在多余内容(位于 31) |
逗号连接或 INNER JOIN … ON 1=1 |
TOP n PERCENT |
TOP n PERCENT 不支持,请改写为 LIMIT(位于 14) |
ORDER BY … LIMIT 百分比行数 |
dbo. / 跨库前缀 |
表名 'dbo' 带库/架构前缀,dbsql 不支持跨库引用(请改写为同库表名) |
同库裸表名 |
TRUNCATE TABLE |
不支持的 SQL 语句类型:TRUNCATE |
DELETE FROM t |
CREATE UNIQUE INDEX |
CREATE 后必须是 DATABASE / TABLE / INDEX / VIEW / PROCEDURE / FUNCTION / TRIGGER / SCHEDULE |
建表时写 UNIQUE 约束 |
DROP INDEX |
不支持 | 重建表 / 不建该索引 |
CREATE OR REPLACE VIEW |
不支持 | DROP VIEW + CREATE VIEW |
DROP TABLE IF EXISTS |
不支持 | 先查存在性再删 |
MERGE |
不支持 | UPDATE + INSERT 分两步 |
ISNULL(a, b) |
未定义的函数 'ISNULL' |
COALESCE(a, b) |
SET QUOTED_IDENTIFIER |
见 2.8 | 字符串统一用单引号 |
窗口 PARTITION BY |
ROW_NUMBER 的 PARTITION BY 暂不支持 |
分组后分别编号 / 应用层处理 |
顶层 EXEC p |
不支持的 SQL 语句类型:EXEC |
CALL p() |
| 一条命令多条语句 | SELECT 语句末尾存在多余内容 |
一次一条 |
| 外键 | 见 总览第 5 节 | NOT NULL + 应用层校验 |
4. 与 SQL Server 有差异的地方
| 主题 | 本引擎(T-SQL 方言) | SQL Server |
|---|---|---|
| 列默认可空性 | 默认 NOT NULL:CREATE TABLE t (id INT PRIMARY KEY, v VARCHAR(5)) 后,INSERT INTO t (id) VALUES (1) 报 列 'v' 不允许为空(未提供值且无默认值),显式写 NULL 同样被拒;要空值必须建表时声明 NULL |
默认 NULL |
CHAR(n) |
单字符类型;CHAR(3) 插入 'abcd' 报 列 'ch' 为字符列,字面量必须是单个字符,如 'a' |
定长 n,短补空格、长截断 |
VARCHAR(n) / NVARCHAR(n) |
只解析不校验,VARCHAR(5) 可存 abcdefgh |
超长报错或截断 |
DECIMAL(p,s) 超小数位 |
报错:小数位 3 超过声明小数位 2,不四舍五入 |
按 s 四舍五入 |
| 双引号 | 字符串字面量(SELECT "id" 返回 id),且不能开 QUOTED_IDENTIFIER |
QUOTED_IDENTIFIER ON 时是标识符 |
TINYINT |
有符号单字节 | 0–255 无符号 |
FLOAT |
DDL 落单精度;CONVERT(FLOAT, …) 落双精度 |
默认 float(53)(双精度) |
字符串比较 / LIKE |
区分大小写 | 取决于排序规则(安装默认多不区分) |
PRINT |
求值后丢弃,不输出到客户端 | 输出到消息流 |
| 事务作用域 | 进程级单事务,CLI 跨命令即丢失 | 会话级,可跨批 |
ISNULL |
不存在 | 存在 |
TOP n PERCENT / MERGE / TRUNCATE |
不支持 | 支持 |
| 触发器伪表 | NEW.col / OLD.col |
inserted / deleted |
| 触发器体 | 仅 INSERT/UPDATE/DELETE/RAISE,每条前需 AS 引导 |
任意 T-SQL 块 |
| 过程调用 | CALL p()(EXEC 只在过程体内) |
EXEC p |
| 与 SQL Server 一致的部分 | NULL 排序(ASC NULL 在前)、TOP、OFFSET/FETCH、[名字]、N'…'、IDENTITY、dbo 之外的常规语法 |
— |
5. 迁移建议
- 把
ISNULL换成COALESCE;把TOP n PERCENT改成先算行数再LIMIT。 - 建表脚本里显式写出可空性:本引擎默认
NOT NULL,与 SQL Server 相反。 - 依赖
CHAR(n)定长语义的列,改用VARCHAR并在应用层补位/裁剪。 - 长度/精度约束在应用层再校验一遍(
VARCHAR(n)、DECIMAL(p,s)中只有后者生效)。 - 双引号标识符改成
[名字]或裸名字;SET QUOTED_IDENTIFIER整行删掉。 - 触发器重写成
BEFORE|AFTER … AS <stmt>形式,伪表改NEW/OLD。 - 顶层
EXEC p改成CALL p();过程定义补空参数括号。 - 去掉
dbo.前缀与跨库引用。
6. 复现
cd /path/to/dbsql
./target/release/dbsql --root /tmp/dbsql-dialect-verify create database tdb
./target/release/dbsql --root /tmp/dbsql-dialect-verify sql tdb "CREATE TABLE t (id INT PRIMARY KEY, v VARCHAR(5))"
./target/release/dbsql --root /tmp/dbsql-dialect-verify sql tdb "INSERT INTO t (id) VALUES (1)"
# 错误:第 1 行的列 'v' 不允许为空(未提供值且无默认值)
完整清单:verify.sh。