You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

能否在存储过程调用中传入Table-Valued Parameter字面量?

如何用简洁方式给SQL Server存储过程传入表参数字面量?

背景

我常看到Table-Valued Parameter(表值参数,TVP)被推荐作为向SQL Server存储过程传递多值参数的方式,但从未在实际项目中见过。在我参与过的多个项目里,多值参数最常以逗号分隔列表(可自选分隔符)传递,偶尔也会用XML或JSON(可容纳更复杂的值)。这些参数通常会被解析后填充到表变量中再使用,有时也会在存储过程体内直接解析(仅引用一次时)。我推测TVP未被广泛使用的原因可能包括其认知度低、存在学习曲线,以及使用不便。我的问题正与最后一点相关。

问题

我在创建或修改存储过程时,偏好使用EXEC MyProcedure TestValue1, TestValue2, TestValue3, ...这类单行调用进行冒烟测试,或执行多个类似的简单测试。若参数中有Table-Valued Parameter,是否可以为该参数提供字面量值?

例如,给定以下类型和存储过程定义:

CREATE TYPE IntList AS TABLE(Value INT)
CREATE TYPE StringList AS TABLE(Value NVARCHAR(MAX))

CREATE PROCEDURE MyProcedure
    @IntValues IntList READONLY,
    @StringValues StringList READONLY
AS
    SELECT
        (SELECT MAX(Value) FROM @IntValues) AS MaxInt,
        (SELECT MAX(Value) FROM @StringValues) AS MaxString

可以通过以下多语句测试:

DECLARE @IntValues IntList
DECLARE @StringValues StringList
INSERT @IntValues VALUES (1), (2)
INSERT @StringValues VALUES ('aaa'), ('bbb'), ('ccc')
EXEC MyProcedure @IntValues, @StringValues

我更希望用单行语句测试,类似:

EXEC MyProcedure (1, 2), ('aaa', 'bbb', 'ccc')
-- 或
EXEC MyProcedure (VALUES (1), (2)), (VALUES ('aaa'), ('bbb'), ('ccc'))

上述写法显然不符合语法规范,但有没有简洁的方式传入表参数字面量?

解决方案

SQL Server不支持直接用字面量集合作为表值参数传入存储过程,但可以通过以下几种技巧实现接近单行的简洁测试方式:

1. 紧凑化声明+插入+执行语句

将变量声明、插入数据和存储过程调用用分号合并成一行,虽然仍需显式声明表变量,但实现了单行调用的需求:

DECLARE @IntValues IntList; INSERT @IntValues VALUES (1),(2); DECLARE @StringValues StringList; INSERT @StringValues VALUES ('aaa'),('bbb'),('ccc'); EXEC MyProcedure @IntValues, @StringValues;

2. 封装内联表值函数生成TVP数据

创建辅助函数来快速将字符串列表(或其他格式)转换为对应的表值参数类型,之后就能用单行调用传入:
首先创建转换函数:

CREATE FUNCTION dbo.CreateIntList(@values NVARCHAR(MAX))
RETURNS @result IntList
AS
BEGIN
    INSERT INTO @result
    SELECT value FROM STRING_SPLIT(@values, ',') WHERE TRY_CAST(value AS INT) IS NOT NULL
    RETURN
END

CREATE FUNCTION dbo.CreateStringList(@values NVARCHAR(MAX))
RETURNS @result StringList
AS
BEGIN
    INSERT INTO @result
    SELECT value FROM STRING_SPLIT(@values, ',')
    RETURN
END

然后调用存储过程时可以写成:

EXEC MyProcedure @IntValues = dbo.CreateIntList('1,2'), @StringValues = dbo.CreateStringList('aaa,bbb,ccc');

这种方式最接近你想要的简洁字面量传递体验,适合频繁的冒烟测试场景。

3. 使用OPENROWSET(不推荐日常测试)

通过OPENROWSET执行查询生成表数据,但需要提前开启Ad Hoc Distributed Queries配置,步骤繁琐且安全性有限,仅适合特殊场景:

EXEC MyProcedure 
    @IntValues = (SELECT Value FROM OPENROWSET('SQLNCLI', 'Server=(local);Trusted_Connection=yes;', 'SELECT 1 AS Value UNION ALL SELECT 2')),
    @StringValues = (SELECT Value FROM OPENROWSET('SQLNCLI', 'Server=(local);Trusted_Connection=yes;', 'SELECT ''aaa'' AS Value UNION ALL SELECT ''bbb'' UNION ALL SELECT ''ccc'''));

补充说明

表值参数的设计初衷是为了高效地从应用程序(如C#)传递批量数据(例如用DataTable作为参数传入),而非针对T-SQL环境下的字面量简洁调用优化。如果仅用于测试,上述第一种紧凑写法或第二种封装函数的方式是最实用的选择。

内容的提问来源于Stack Exchange,提问作者T N

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 20:17:47