Skip to content

调用存储过程

存储过程适合封装复杂的数据库逻辑——多步操作、条件分支、数据验证和跨表事务。本教程演示如何将一个业务存储过程发布为 API,并在 REST 和 GraphQL 中调用。

场景

图书管理系统需要一个功能:根据作者姓名查询该作者参与合著的所有书籍。这个查询涉及多表关联和字符串匹配,用一个存储过程封装更合适。

第一步:创建存储过程

sql
CREATE PROCEDURE dbo.stp_GetCowrittenBooksByAuthor
    @author_name nvarchar(200),
    @search_type nvarchar(20) = 'all',
    @min_year int = null
AS
BEGIN
    SELECT DISTINCT
        b.id,
        b.title,
        b.[year],
        b.pages,
        a.name AS author_name
    FROM dbo.Books b
        INNER JOIN dbo.Book_Authors ba ON b.id = ba.book_id
        INNER JOIN dbo.Authors a ON ba.author_id = a.id
    WHERE a.name LIKE '%' + @author_name + '%'
        AND (@search_type = 'all' OR b.genre = @search_type)
        AND (@min_year IS NULL OR b.[year] >= @min_year)
    ORDER BY b.[year] DESC;
END

存储过程接受三个参数:

  • @author_name(必填):作者姓名,支持模糊匹配。
  • @search_type(可选,默认 'all'):按类型筛选。
  • @min_year(可选):最小出版年份。

第二步:添加存储过程实体

bash
dab add GetCowrittenBooksByAuthor \
  --source "dbo.stp_GetCowrittenBooksByAuthor" \
  --source.type "stored-procedure" \
  --parameters.name "author_name,search_type,min_year" \
  --parameters.required "true,false,false" \
  --parameters.default ",all,null" \
  --permissions "anonymous:execute" \
  --rest.methods "GET" \
  --graphql.operation "query"

参数说明:

  • author_name 是必填(required: true),调用时必须提供。
  • search_typemin_year 有默认值,可以省略。
  • REST 使用 GET 方法(更适合纯查询类存储过程)。
  • GraphQL 挂载在 query 下(同样因为是纯查询)。

第三步:启动并测试

bash
dab start

REST 调用

GET 方式(参数通过查询字符串)

bash
# 只传必填参数
curl "http://localhost:5000/api/GetCowrittenBooksByAuthor?author_name=张三"

# 传全部参数
curl "http://localhost:5000/api/GetCowrittenBooksByAuthor?author_name=李四&search_type=fiction&min_year=2000"

POST 方式(如果配置了 POST)

bash
curl -X POST http://localhost:5000/api/GetCowrittenBooksByAuthor \
  -H "Content-Type: application/json" \
  -d '{"author_name": "张三", "search_type": "fiction", "min_year": 2000}'

GraphQL 调用

存储过程在 GraphQL 中自动加上 execute 前缀:

graphql
{
  executeGetCowrittenBooksByAuthor(
    author_name: "张三"
    search_type: "fiction"
    min_year: 2000
  ) {
    id
    title
    year
    author_name
  }
}

变量形式:

graphql
query GetBooks($author: String!, $type: String) {
  executeGetCowrittenBooksByAuthor(
    author_name: $author
    search_type: $type
  ) {
    id title year author_name
  }
}

第四步:添加语义描述

为了让 MCP 代理更好地理解这个存储过程,补充描述:

bash
dab update GetCowrittenBooksByAuthor \
  --description "根据作者姓名查询该作家的全部合著书籍,包括书名、出版年份和作者名" \
  --parameters.description "作者姓名(支持模糊匹配,如'张'可匹配'张三'和'张四'),书籍类型筛选(fiction/nonfiction,默认all不筛选),最小出版年份(null不设下限)"

权限注意事项

存储过程使用独立的 execute 权限,与表实体的 CRUD 权限分离:

json
{
  "permissions": [
    { "role": "anonymous", "actions": ["execute"] }
  ]
}
  • * 通配符对存储过程仅扩展为 execute,不会意外授予 CRUD 权限。
  • 如果存储过程内部包含数据修改逻辑(INSERT/UPDATE/DELETE),用户不需要额外的 create/update 权限——execute 权限即允许执行过程内的全部操作。请确保授予 execute 的角色确实有权执行该过程。

限制和注意事项

限制替代方案
不支持分页筛选排序如果查询需要这些能力,将查询逻辑改写为视图
仅返回第一个结果集多结果集的过程需要拆分为多个独立过程
需要 sys.dm_exec_describe_first_result_set 元数据SQL Server 需确保该函数对连接用户可执行
仅 SQL Server 支持PostgreSQL 和 MySQL 用户需使用视图或函数替代

如果需要对存储过程的输出进行筛选、分页和排序,更好的方案是将核心查询逻辑写成视图,用视图实体暴露 API,同时保留存储过程用于需要过滤后结果的特定场景。

下一步

数据墙DBW 产品文档与开发指南。