关于 sap-sqlscript
面向 SAP HANA 开发者的 SQLScript 技能,涵盖过程式数据库逻辑、AMDP 与性能实践。附带语法、排错和优化参考资料,适用于将数据处理逻辑部署在数据库层。
主要功能
- 01匿名块、存储过程与函数
- 02变量、游标和异常处理
- 03AMDP 集成指导
- 04声明式 SQL 性能实践
- 05内置参考资料与排错指南
适用场景
- 01编写 HANA 存储过程和函数
- 02实现 AMDP 数据库逻辑
- 03排查 SQLScript 异常
- 04优化数据密集型查询
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ secondsky/ sap-skills --skill sap-sqlscript安装后在 Claude Code 中输入/sap-sqlscript确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
README.mdagents/openai.yamlreferences/advanced-features.mdamdp-integration.mdbuilt-in-functions.mddata-types.mdedge-cdp-control.mdexception-handling.mdglossary.mdperformance-guide.mdskill-reference-guide.mdsyntax-reference.mdtroubleshooting.mdtemplates/amdp-class.abapamdp-procedure.sqlbulk-operations.sqlcursor-iteration.sqlprocedure-with-error-handling.sqlscalar-function.sqlsimple-procedure.sqltable-function.sql详细介绍
SAP SQLScript 开发指南
何时使用此技能
在编写 SQLScript 过程、匿名块、表函数/标量函数、AMDP 方法、异常处理程序、游标逻辑、批量操作,或需要在靠近数据的位置运行且对 HANA 性能敏感的数据库逻辑时,使用此技能。
对于基于浏览器的 Datasphere 或 HANA Cloud SQL 编辑器问题排查,请使用 sap-browser-automation,以处理应用内手动身份验证、需经用户同意的 Edge 配置文件复用、全新 Edge/CDP 启动、身份验证状态引导和恢复。加载本地 references/edge-cdp-control.md,了解 SQLScript 专属边界。CDP 仅用于本地 UI 检查、控制台诊断、部署消息和经批准的截图;默认情况下,数据库验证仍应使用 SQL/HANA 工具。
概述
SQLScript 是 SAP HANA 对 SQL 的过程式扩展,可在数据库层直接执行复杂的数据密集型逻辑。它遵循代码到数据范式,将计算推送到数据所在的位置,而不是将数据移至应用层。
主要特征
- 不区分大小写
- 所有语句都以分号结尾
- 引用变量时使用冒号前缀(
:variableName) - 赋值时不加冒号
- 单行操作使用
DUMMY表
两种逻辑类型
| 类型 | 描述 | 执行方式 |
|---|---|---|
| 声明式 | 纯 SQL 序列 | 转换为数据流图,并行处理 |
| 命令式 | 控制结构(IF、WHILE、FOR) | 按顺序处理,会阻止并行执行 |
目录
容器类型
1. 匿名块
仅使用一次、不存储在数据库中的逻辑。适用于测试和临时执行。
DO [(<parameter_clause>)]
BEGIN [SEQUENTIAL EXECUTION]
<body>
END;
示例:
DO
BEGIN
DECLARE lv_count INTEGER;
SELECT COUNT(*) INTO lv_count FROM "MYTABLE";
SELECT :lv_count AS record_count FROM DUMMY;
END;
2. 存储过程
带有输入/输出参数、可重复使用的数据库对象。
CREATE [OR REPLACE] PROCEDURE <procedure_name>
(
[IN <param> <datatype>],
[OUT <param> <datatype>],
[INOUT <param> <datatype>]
)
LANGUAGE SQLSCRIPT
[SQL SECURITY {DEFINER | INVOKER}]
[DEFAULT SCHEMA <schema_name>]
[READS SQL DATA | READS SQL DATA WITH RESULT VIEW <view_name>]
AS
BEGIN
<procedure_body>
END;
3. 用户定义函数
标量 UDF - 返回单个值:
CREATE FUNCTION <function_name> (<input_parameters>)
RETURNS <scalar_type>
LANGUAGE SQLSCRIPT
AS
BEGIN
<function_body>
RETURN <value>;
END;
表 UDF - 返回表(只读):
CREATE FUNCTION <function_name> (<input_parameters>)
RETURNS TABLE (<column_definitions>)
LANGUAGE SQLSCRIPT
READS SQL DATA
AS
BEGIN
RETURN SELECT ... FROM ...;
END;
数据类型
SQLScript 支持多种数据类型,可用于不同场景。完整文档请参阅 references/data-types.md,其中包括:
- 数值类型(TINYINT、INTEGER、DECIMAL 等)
- 字符类型(VARCHAR、NVARCHAR、CLOB 等)
- 日期/时间类型(DATE、TIME、TIMESTAMP、SECONDDATE)
- 二进制类型(VARBINARY、BLOB)
- 类型转换函数(CAST、TO_ 函数)
- NULL 处理模式
变量声明
标量变量
DECLARE <variable_name> <datatype> [:= <initial_value>];
-- Examples
DECLARE lv_name NVARCHAR(100);
DECLARE lv_count INTEGER := 0;
DECLARE lv_date DATE := CURRENT_DATE;
注意: 未初始化的变量默认为 NULL。
表变量
隐式声明:
lt_result = SELECT * FROM "MYTABLE" WHERE status = 'A';
显式声明:
DECLARE lt_data TABLE (
id INTEGER,
name NVARCHAR(100),
amount DECIMAL(15,2)
);
使用 TABLE LIKE:
DECLARE lt_copy TABLE LIKE :lt_original;
数组
DECLARE arr INTEGER ARRAY := ARRAY(1, 2, 3, 4, 5);
-- Access: arr[1], arr[2], etc. (1-based index)
-- Note: Arrays cannot be returned from procedures
控制结构
IF-ELSE 语句
IF <condition1> THEN
<statements>
[ELSEIF <condition2> THEN
<statements>]
[ELSE
<statements>]
END IF;
比较运算符:
| 运算符 | 含义 |
|---|---|
= | 等于 |
> | 大于 |
< | 小于 |
>= | 大于或等于 |
<= | 小于或等于 |
!=, <> | 不等于 |
重要: IF-ELSE 不能在 SELECT 语句中使用。请改用 CASE WHEN。
WHILE 循环
WHILE <condition> DO
<statements>
END WHILE;
FOR 循环
-- Numeric range
FOR i IN 1..10 DO
<statements>
END FOR;
-- Reverse
FOR i IN REVERSE 10..1 DO
<statements>
END FOR;
-- Cursor iteration
FOR row AS <cursor_name> DO
<statements using row.column_name>
END FOR;
带 EXIT 的 LOOP
LOOP
<statements>
IF <condition> THEN
BREAK;
END IF;
END LOOP;
表类型
定义可重复使用的表结构:
CREATE TYPE <type_name> AS TABLE (
<column1> <datatype>,
<column2> <datatype>,
...
);
在过程中使用:
CREATE PROCEDURE get_employees (OUT et_result MY_TABLE_TYPE)
LANGUAGE SQLSCRIPT AS
BEGIN
et_result = SELECT * FROM "EMPLOYEES";
END;
游标
游标逐行处理结果集。模式:声明 → 打开 → 获取 → 关闭
**性能提示:**游标会绕过数据库优化器,按顺序处理行。主要用于基于主键的查询。尽可能优先使用基于集合的操作。
DECLARE CURSOR <cursor_name> FOR
SELECT <columns> FROM <table> [WHERE <condition>];
OPEN <cursor_name>;
FETCH <cursor_name> INTO <variables>;
CLOSE <cursor_name>;
完整示例:
DO
BEGIN
DECLARE lv_id INTEGER;
DECLARE lv_name NVARCHAR(100);
DECLARE CURSOR cur_employees FOR
SELECT id, name FROM "EMPLOYEES" WHERE dept = 'IT';
OPEN cur_employees;
FETCH cur_employees INTO lv_id, lv_name;
WHILE NOT cur_employees::NOTFOUND DO
-- Process row
SELECT :lv_id, :lv_name FROM DUMMY;
FETCH cur_employees INTO lv_id, lv_name;
END WHILE;
CLOSE cur_employees;
END;
FOR 循环替代方案:
FOR row AS cur_employees DO
SELECT row.id, row.name FROM DUMMY;
END FOR;
异常处理
EXIT HANDLER
发生异常时暂停执行并进行清理。
DECLARE EXIT HANDLER FOR <condition_value>
<statement>;
条件值:
SQLEXCEPTION- 任何 SQL 异常SQL_ERROR_CODE <number>- 特定错误代码
访问错误详情:
::SQL_ERROR_CODE- 数字错误代码::SQL_ERROR_MESSAGE- 错误消息文本
示例:
CREATE PROCEDURE safe_insert (IN iv_id INTEGER, IN iv_name NVARCHAR(100))
LANGUAGE SQLSCRIPT AS
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
SELECT ::SQL_ERROR_CODE AS err_code,
::SQL_ERROR_MESSAGE AS err_msg FROM DUMMY;
END;
INSERT INTO "MYTABLE" VALUES (:iv_id, :iv_name);
END;
CONDITION
将用户定义的名称与错误代码关联:
DECLARE <condition_name> CONDITION FOR SQL_ERROR_CODE <number>;
-- Example
DECLARE duplicate_key CONDITION FOR SQL_ERROR_CODE 301;
DECLARE EXIT HANDLER FOR duplicate_key
SELECT 'Duplicate key error' FROM DUMMY;
SIGNAL 和 RESIGNAL
抛出用户定义的异常(代码 10000-19999):
-- Throw exception
SIGNAL <condition_name> SET MESSAGE_TEXT = '<message>';
-- Re-throw in handler
RESIGNAL [<condition_name>] [SET MESSAGE_TEXT = '<message>'];
常见错误代码:
| 代码 | 描述 |
|---|---|
| 301 | 唯一约束冲突 |
| 1299 | 未找到数据 |
AMDP 集成
ABAP 托管数据库过程允许在 ABAP 类中使用 SQLScript。
类定义
CLASS zcl_my_amdp DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES if_amdp_marker_hdb. " Required interface
TYPES: BEGIN OF ty_result,
id TYPE i,
name TYPE string,
END OF ty_result,
tt_result TYPE STANDARD TABLE OF ty_result.
CLASS-METHODS: get_data
IMPORTING VALUE(iv_filter) TYPE string
EXPORTING VALUE(et_result) TYPE tt_result.
ENDCLASS.
方法实现
CLASS zcl_my_amdp IMPLEMENTATION.
METHOD get_data BY DATABASE PROCEDURE
FOR HDB
LANGUAGE SQLSCRIPT
OPTIONS READ-ONLY
USING ztable.
et_result = SELECT id, name
FROM ztable
WHERE category = :iv_filter;
ENDMETHOD.
ENDCLASS.
AMDP 限制
- 参数必须采用传值方式(不支持 RETURNING)
- 仅允许使用标量类型、结构、内表
- 不允许嵌套表或深层结构
- 不允许使用 COMMIT/ROLLBACK
- 开发必须使用 Eclipse ADT
- 首次调用时自动创建
性能最佳实践
1. 尽早减少数据量
-- Good: Filter and project early
lt_filtered = SELECT col1, col2 FROM "BIGTABLE" WHERE status = 'A';
lt_result = SELECT a.col1, b.name
FROM :lt_filtered AS a
JOIN "LOOKUP" AS b ON a.id = b.id;
-- Bad: Join then filter
lt_result = SELECT a.col1, b.name
FROM "BIGTABLE" AS a
JOIN "LOOKUP" AS b ON a.id = b.id
WHERE a.status = 'A';
2. 优先使用声明式而非命令式
-- Good: Set-based operation
lt_result = SELECT id, amount * 1.1 AS new_amount FROM "ORDERS";
-- Bad: Row-by-row processing
FOR row AS cur_orders DO
UPDATE "ORDERS" SET amount = row.amount * 1.1 WHERE id = row.id;
END FOR;
3. 避免混用引擎
- 不要在同一查询中混用行存储表和列存储表
- 避免在纯 SQL 中使用计算引擎函数
- 使用一致的存储类型
4. 使用 UNION ALL 替代 UNION
-- Faster when duplicates impossible or acceptable
SELECT * FROM table1 UNION ALL SELECT * FROM table2;
-- Slower: removes duplicates
SELECT * FROM table1 UNION SELECT * FROM table2;
5. 避免动态 SQL
-- Bad: Re-optimized each execution
EXECUTE IMMEDIATE 'SELECT * FROM ' || :lv_table;
-- Good: Static SQL with parameters
SELECT * FROM "MYTABLE" WHERE id = :lv_id;
6. 将命令式逻辑放在最后
将控制结构放在过程末尾,以最大限度地并行处理声明式语句。
系统限制
| 限制 | 值 |
|---|---|
| 每笔事务的表锁数量 | 16,383 |
| 单条语句中的表数量 | 4,095 |
| SQL 语句长度 | 2 GB |
| 过程大小 | 受 SQL 语句长度限制(2 GB) |
**注意:**实际限制可能因 HANA 版本而异。请查阅 SAP 文档,了解特定版本的限制。
调试工具
- SQLScript 调试器 - SAP Web IDE / Business Application Studio
- 计划可视化工具 - 分析执行计划
- 昂贵语句跟踪 - 识别瓶颈
- SQL 分析器 - 查询优化建议
快速参考
字符串拼接
lv_result = lv_str1 || ' ' || lv_str2;
NULL 处理
COALESCE(value, default_value)
IFNULL(value, default_value)
NULLIF(value1, value2)
日期操作
ADD_DAYS(date, n)
ADD_MONTHS(date, n)
DAYS_BETWEEN(date1, date2)
CURRENT_DATE
CURRENT_TIMESTAMP
类型转换
CAST(value AS datatype)
TO_VARCHAR(value)
TO_INTEGER(value)
TO_DATE(string, 'YYYY-MM-DD')
TO_TIMESTAMP(string, 'YYYY-MM-DD HH24:MI:SS')
相关技能
要全面开展 SAP 开发,请将此技能与以下技能结合使用:
| 技能 | 使用场景 |
|---|---|
| sap-abap | AMDP 场景下的 ABAP 编程模式 |
| sap-abap-cds | 使用 SQLScript 过程的 CDS 视图 |
| sap-cap-capire | CAP 框架数据库过程集成 |
| sap-hana-cli | 用于过程部署和测试的 HANA CLI |
| sap-btp-cloud-platform | HANA 构件的 BTP 部署 |
捆绑资源
参考文档
references/skill-reference-guide.md- 所有参考资料的索引,支持快速导航references/glossary.md- SQLScript 术语和概念references/syntax-reference.md- 完整的 SQLScript 语法参考references/built-in-functions.md- 内置函数目录references/data-types.md- 数据类型和转换references/exception-handling.md- 异常处理模式references/amdp-integration.md- AMDP 集成模式references/performance-guide.md- 优化技巧references/advanced-features.md- 横向连接、JSON、查询提示、货币转换references/troubleshooting.md- 常见错误和解决方案references/edge-cdp-control.md- 用于共享sap-browser-automationEdge/CDP 和身份验证层的 SQLScript 专用扩展
可用于生产环境的模板
复制并自定义这些模板,以用于常见模式:
templates/simple-procedure.sql- 带错误处理的基本存储过程templates/procedure-with-error-handling.sql- 全面的错误处理模式templates/table-function.sql- 带验证的表 UDFtemplates/scalar-function.sql- 标量 UDF 示例templates/amdp-class.abap- 完整的 AMDP 类样板代码templates/amdp-procedure.sql- AMDP 实现模板templates/cursor-iteration.sql- 游标模式(经典模式和 FOR 循环)templates/bulk-operations.sql- 高性能批量操作
专用 Agent
- sqlscript-analyzer - 分析代码中的性能问题和最佳实践
- procedure-generator - 根据需求交互式生成过程
- amdp-helper - 协助创建和调试 AMDP 类
斜杠命令
/sqlscript-validate- 验证代码并支持自动修复/sqlscript-optimize- 性能分析和优化建议/sqlscript-convert- 在独立格式和 AMDP 格式之间转换
验证钩子
在 Write/Edit 操作时自动执行代码质量检查:
- 错误处理完整性
- 安全漏洞
- 性能反模式
- 命名约定
- AMDP 合规性