Sql 触发器只在表中插入变量的1个字符

Sql 触发器只在表中插入变量的1个字符,sql,sql-server,sql-server-2014,sqr,Sql,Sql Server,Sql Server 2014,Sqr,我有以下sql触发器,它根据在相关表上发生的删除操作,将数据插入名为PS\u AUDIT\u PSROLEUSR的表中 当应用程序中的在线用户触发表更新(删除角色行)时,整个OPRID将正确插入PS\u AUDIT\u PSROLEUSR,但是,当触发器通过我编写的批处理程序运行时,它只获得AUDIT\u OPRID的第一个字母。我已经通过在另一个OPRID下运行该程序确认了这一点,它仍然只在列中插入第一个字符。请原谅我不太熟悉SQL触发器 ALTER TRIGGER [dbo].[PSROLE

我有以下sql触发器,它根据在相关表上发生的删除操作,将数据插入名为
PS\u AUDIT\u PSROLEUSR
的表中

当应用程序中的在线用户触发表更新(删除角色行)时,整个OPRID将正确插入
PS\u AUDIT\u PSROLEUSR
,但是,当触发器通过我编写的批处理程序运行时,它只获得
AUDIT\u OPRID
的第一个字母。我已经通过在另一个
OPRID
下运行该程序确认了这一点,它仍然只在列中插入第一个字符。请原谅我不太熟悉SQL触发器

ALTER TRIGGER [dbo].[PSROLEUSER_TR] 
ON [dbo].[PSROLEUSER]
FOR INSERT, UPDATE, DELETE
AS
    SET NOCOUNT ON

    DECLARE @XTYPE CHAR(1), @OPRID CHAR(30)

    SET @OPRID = NULL

    SELECT @OPRID = CASE(CHARINDEX(',', CAST(context_info AS CHAR(128))))
                       WHEN 0 THEN 'Native SQL'
                       ELSE SUBSTRING(CAST(context_info AS CHAR(128)), 1, (CHARINDEX(',', CAST(context_info AS CHAR(128)))-1))
                    END
    FROM sys.sysprocesses
    WHERE spid = @@spid

    -- Determine Transaction Type
    IF EXISTS (SELECT * FROM DELETED)
    BEGIN
        SET @XTYPE = 'D'
    END

    IF EXISTS (SELECT * FROM INSERTED)
    BEGIN
        IF (@XTYPE = 'D')
        BEGIN
            SET @XTYPE = 'U'
        END
        ELSE
        BEGIN
            SET @XTYPE = 'I'
        END
    END

    -- Transaction is a Delete
    IF (@XTYPE = 'D')
    BEGIN
        INSERT INTO PS_AUDIT_PSROLEUSR (AUDIT_OPRID, AUDIT_STAMP, AUDIT_ACTN, ROLEUSER, ROLENAME, DYNAMIC_SW)
            SELECT 
                @OPRID, 
                DATEADD(SECOND, ROW_NUMBER() OVER (ORDER BY @OPRID), GETDATE()), 
                'D', ROLEUSER, ROLENAME, DYNAMIC_SW 
            FROM 
                deleted 
    END

    -- Transaction is a Insert
    IF (@XTYPE = 'I')
    BEGIN
        INSERT INTO PS_AUDIT_PSROLEUSR (AUDIT_OPRID, AUDIT_STAMP, AUDIT_ACTN, ROLEUSER, ROLENAME, DYNAMIC_SW)
             SELECT 
                 @OPRID, GETDATE(),
                 'A', ROLEUSER, ROLENAME, DYNAMIC_SW 
             FROM 
                 inserted 
    END

    -- Transaction is a Update
    IF (@XTYPE = 'U')
    BEGIN
        -- Before Update
        INSERT INTO PS_AUDIT_PSROLEUSR (AUDIT_OPRID, AUDIT_STAMP, AUDIT_ACTN, ROLEUSER, ROLENAME, DYNAMIC_SW)
            SELECT 
                @OPRID, GETDATE(), 'K',
                ROLEUSER, ROLENAME, DYNAMIC_SW 
            FROM 
                deleted 
        -- After Update
        INSERT INTO PS_AUDIT_PSROLEUSR (AUDIT_OPRID, AUDIT_STAMP, AUDIT_ACTN, ROLEUSER, ROLENAME, DYNAMIC_SW)
            SELECT 
                @OPRID, GETDATE(), 'N',
                ROLEUSER, ROLENAME, DYNAMIC_SW 
            FROM 
                inserted 
    END
插入
PS\u AUDIT\u PSROLEUSR

AUDIT_OPRID AUDIT_STAMP              AUDIT_ACTN ROLEUSER    ROLENAME    DYNAMIC_SW
K           2019-04-25 08:33:08.340  D          LTESTUSER   EUSER       N
K           2019-04-25 08:33:09.340  D          LTESTUSER   EPRO        N
我似乎无法访问
SELECT*FROM DELETED
中的“DELETE”表,因此我不确定这是否只是在运行时动态生成的

旁注-有点奇怪的是,我查询PS_AUDIT_PSROLEUSR的值'K'如下,我得到0行返回。我检查过信后面没有空格

    SELECT *
    FROM PS_AUDIT_PSROLEUSR
    WHERE AUDIT_OPRID = 'K'
如果我使用
LIKE
运算符,则仅获取“K”的数据

-- Results in 0 rows
编辑:如果我运行下面的代码,我得到的行长度为12个字符,并用“K”插入,因此添加了额外的尾随空格

SELECT LEN(AUDIT_OPRID),*
FROM PS_AUDIT_PSROLEUSR
WHERE AUDIT_OPRID  like 'K%'  
我还尝试将这个简单的IF语句添加到触发器中,但是它似乎也不起作用:我认为从binary(context_info)到varchar的转换将允许逻辑过滤掉值“K”

IF (CONVERT(VARCHAR(256),@OPRID)) <> 'K' 
BEGIN
IF(CONVERT(VARCHAR(256),@OPRID))'K'
开始

这不一定是触发器的问题,而是批处理应用程序设置的
上下文信息
二进制值的字符编码问题。当
CONTEXT\u INFO
值实际上是一个Unicode字符串,并且二进制值随后在T-SQL中转换为
CHAR
时,就会出现这些症状

考虑这个例子:

DECLARE @ContextInfo varbinary(128) = CAST(N'ABC,DEF,GHI' AS varbinary(128));
SET CONTEXT_INFO @ContextInfo;
GO

DECLARE @OPRID CHAR(30) = NULL;
SELECT CAST(context_info AS CHAR(30)) AS CharValue, CAST(context_info AS NCHAR(30)) AS NCharValue 
FROM sys.sysprocesses
WHERE spid = @@spid;
GO
结果:

+-----------+-------------+
| CharValue | NCharValue  |
+-----------+-------------+
| A         | ABC,DEF,GHI |
+-----------+-------------+
要解决此问题,您可以将应用程序代码更改为将
CONTEXT\u INFO
设置为ANSI字符串,或将T-SQL大小写表达式更改为
CAST
将值设置为
NCHAR
。下面是一个T-SQL示例,它实现了这一点,并且还使用了
sys.dm_exec_sessions
DMV,而不是
sys.processs
,后者已经被弃用了15年

SELECT @OPRID = CASE(CHARINDEX(',', CAST(context_info AS NCHAR(64))))
                   WHEN 0 THEN N'Native SQL'
                   ELSE SUBSTRING(CAST(context_info AS NCHAR(64)), 1, (CHARINDEX(',', CAST(context_info AS NCHAR(64)))-1))
                END
FROM sys.dm_exec_sessions
WHERE session_id = @@spid;

尾随空格很可能是由CHAR数据类型创建的。例如,CHAR(30)将用空格填充值,使长度始终为30个字符。如果您不想让它们有额外的空间,您可以使用VARCHAR(30)。旁注-如果您计划使用Unicode字符,将使用NVARCHAR(30)。(前面的“N”表示它将允许使用Unicode字符)。奇怪的是,当用户自己更新应用程序中的数据时,它目前的工作方式很好,它将整个OPRID插入到列中。当批处理程序更新数据时,它只是表现出这种行为。我不打算输出任何unicode字符。在上面的代码中,我看不到任何会导致这种情况的东西。请提供用于在批处理程序中设置上下文信息的代码。我的猜测是您没有正确设置它,或者它被截断了。另外,是的,
inserted
deleted
表是动态创建和填充的,并且仅在某些上下文中可用,作为其中的一员,@pcdev我将不得不做更多的挖掘,因为我真的不知道程序是如何做到这一点的,它必须在比我编写的更低的级别上完成。