2016-01-22 94 views
0

在表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(即使我ltrimrtrim更新前的单个字符值)?

为什么我必须把我的CONTEXT_INFO总共127个字节,而不是128?对于超过127的每一个字符,一个字符从最初设置上CONTEXT_INFO

注意值截断:ANSI_PADDING启用

回答

1

在您的代码:

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)字符填充信BLTRIM()RTRIM()不会删除不为空白的空字符,因此它们对@user没有影响。

如果你想删除NULL字符,你可以试试这个(假设你使用SQL Server 2005或更高版本):

UPDATE users SET username = REPLACE(@user, char(0), '') 
+0

短铸造值的类型不允许空字节,有没有简单的方法来删除所有尾随NULL字节? –

+0

如果你从一个128字节的空填充'CONTEXT_INFO'中选择50个字节,那么你希望有什么作为填充而不是'NULL'?如果你不想填充,那么只需选择确切的长度。 –

+0

但我怎么知道有多少非NULL字符传递到CONTEXT_INFO?在我的示例中,传递的值是硬编码的,但在实时代码中,CONTEXT_INFO使用动态数据填充。 –