SQL Server,CONTEXT_INFO()和varchar大小
问题描述:
在表users
我有一列username
数据类型varchar(50)
。该表没有记录。我用A
作为用户名插入新记录。以下回报我所期望的:SQL Server,CONTEXT_INFO()和varchar大小
SELECT username, LEN(username)
FROM users
WHERE id = 1 -- returns: A, 1
到目前为止好。
现在我从另一个表的触发器更新表的用户,使用从CONTEXT_INFO()
值:
set @context = cast('B' as varbinary(128))
set CONTEXT_INFO @context
update some_other_table
set x = 'y'
where id = 97
在触发some_other_table
我做的:
DECLARE @context VARCHAR(128)
SELECT
@context = CAST(CONTEXT_INFO() AS VARCHAR(128))
FROM
master.dbo.SYSPROCESSES
WHERE
SPID = @@SPID
DECLARE @user VARCHAR(50) = LEFT(@context, 50)
UPDATE users
SET username = LTRIM(RTRIM(@user))
WHERE id = 1
的用户名是否正确设置成“B”,但以下现在返回50:
SELECT
username, LEN(username)
FROM
users
WHERE
id = 1 -- returns: B, 50
解决方案在填充上下文时需要:
set @context = cast('B' + replicate(' ', 126) as varbinary(128))
但是,为什么我需要这样做?
当我不垫CONTEXT_INFO
与空间发生了什么,使用它的值更新将导致生成的长度为50(即使我ltrim
和rtrim
更新前的单个字符值)?
为什么我必须把我的CONTEXT_INFO
总共127个字节,而不是128?对于超过127的每一个字符,一个字符从最初设置上CONTEXT_INFO
注意值截断:ANSI_PADDING启用
答
在您的代码:
declare @user varchar(50) = left(@context, 50)
UPDATE users set username = ltrim(rtrim(@user)) WHERE id = 1
你定义@user
为50个字符。由于CONTEXT_INFO
本身是128个字节,的@user
内容将是49个空CHAR(0)
字符填充信B
。 LTRIM()
和RTRIM()
不会删除不为空白的空字符,因此它们对@user
没有影响。
如果你想删除NULL
字符,你可以试试这个(假设你使用SQL Server 2005或更高版本):
UPDATE users SET username = REPLACE(@user, char(0), '')
短铸造值的类型不允许空字节,有没有简单的方法来删除所有尾随NULL字节? –
如果你从一个128字节的空填充'CONTEXT_INFO'中选择50个字节,那么你希望有什么作为填充而不是'NULL'?如果你不想填充,那么只需选择确切的长度。 –
但我怎么知道有多少非NULL字符传递到CONTEXT_INFO?在我的示例中,传递的值是硬编码的,但在实时代码中,CONTEXT_INFO使用动态数据填充。 –