DEBUG.WIKI
ZgoCloud:多地区部署,按需选节点;日本、美国、香港、德国
雨云;给项目一台云服务器
RackNerd;$21.99/年 · 1GB KVM

SQL Server nvarchar 变量赋值后只剩第一个字符

DECLARE 省略 nvarchar 长度默认容量为1,CAST 的默认值却为30。明确接收长度,区分双字节单位与字符,并从完整来源重新赋值。

SQL Server 查询直接返回 dbo.ImportRows,赋给变量以后却只剩 d。若变量声明写成 DECLARE @label nvarchar,应检查省略的长度:在变量声明中,nvarchar 未指定 n 时默认长度是 1,不会根据随后赋入的字符串自动扩容。

这类截断发生在值进入变量时。先把变量内容读出来,确认是不是已经少了字符,再检查显示工具;扩大结果窗口无法恢复变量中已经丢掉的部分。

比较赋值前后的完整内容

下面是独立的变量示例,不读取或修改业务表:

DECLARE @source nvarchar(128) = N'dbo.ImportRows';
DECLARE @label nvarchar;

SET @label = @source;

SELECT @source AS original_value,
       @label AS assigned_value,
       DATALENGTH(@source) AS original_bytes,
       DATALENGTH(@label) AS assigned_bytes;

这份输入由普通 BMP 字符组成,@label 只能保留开头的 d,占两个字节。对照原值和变量值可以判断截断是否发生在这次赋值;若原值也已经不完整,则要继续向上游查找容量不足的位置。

这里使用 DATALENGTH() 查看实际字节数,而不是把它当字符数。LEN() 会忽略尾部空格,用它单独判断是否完整,也可能漏掉问题。

为接收变量声明明确的容量

按实际数据约定指定长度,例如:

DECLARE @source nvarchar(128) = N'dbo.ImportRows';
DECLARE @label nvarchar(128);

SET @label = @source;
SELECT @label AS assigned_value;

示例的 128 只是已知输入容量,并不适合所有拼接表达式。将两个名称和分隔符拼成标签时,接收变量需要容纳最终结果;不能因为每个部分最多为某个长度,就沿用其中一个部分的容量。

nvarchar(n) 的 n 按双字节单位定义。使用 UTF-16 的补充字符可能占两个这样的单位,所以不能保证 nvarchar(10) 能保存任意十个 Unicode 字符。根据真实输入范围选择容量,并覆盖中文、补充字符及接近上限的样本。

如果业务值确实可能超过 4,000 个双字节单位,再考虑 nvarchar(max)。不要为了修复省略长度就把所有变量、表列和参数统一改成 max;通常明确声明实际需要的有限容量即可。

修好声明后,需要从完整的原始值重新赋值。把已经截成 d 的旧变量转换成更宽类型,只会得到容量更大的 d,不会恢复后面的内容。

CAST 的默认长度与声明不同

另一个容易造成误判的地方是:对 nvarchar,CAST 省略长度时默认是 30,并非声明中的 1。下面两种写法不能用一次测试的表现互相推断:

DECLARE @label nvarchar;
SELECT CAST(N'dbo.ImportRows' AS nvarchar);

短字符串在第二条中看起来完整,并不能证明第一条声明安全。转换时也应明确长度,例如 CAST(@source AS nvarchar(128));还要检查这个转换发生在原始内容丢失之前。

字符串常量表示 Unicode 输入时保留 N 前缀。缺少前缀涉及代码页转换,是另一种内容损失;增加变量长度不能替代正确的字符编码约定。

沿调用链检查接收边界

同一段字符串可能经过查询表达式、局部变量、存储过程参数和应用参数。只扩大最后一个变量,而前一层已经按较短容量接收,仍会得到截断结果。逐层对照值与明确声明的类型、长度,不要只查看源表列的长度。

若变量只是承接一个表字段,可从该字段的数据契约开始核对;若承接的是拼接结果,则核对表达式可能产生的最大长度。这里修的是接收容量,不需要为了修局部变量而先 ALTER 业务表。

在测试环境验证完整值、边界长度、空字符串和 NULL;需要保留尾空格的场景单独比较内容与字节数。确认下游的查询条件、日志标签或导出字段不再只使用首字符,然后再更新相关过程或应用版本。

修改前保存原定义便于回退。如果截断值已经写入其他表或生成文件,代码修复不会自动补齐历史结果;只能从仍保留的完整来源重建,并限定本次受影响范围。