为什么触发器在使用'inserted'表中的字段时尝试插入NULL值?

时间:2012-04-17 21:44:38

标签: sql-server triggers

我必须将MSSQL中完成的更改与远程MySQL数据库同步。要同步的更改是将发票和用户添加到系统。远程服务器不应该总是可以访问,所以我正在尝试设置一种日志表来存储在MSSQL中完成的更改。

这是一个完全有效的触发器:

CREATE TRIGGER [dbo].[dokument_insert]
   ON [dbo].[dokument]
   AFTER INSERT
AS 
BEGIN
    SET NOCOUNT ON;
    INSERT INTO [bcg_ekodu].[dbo].[sync_stack] (event,sql, table_name, import_priority)
        SELECT 
            'INSERT',
            'INSERT INTO bills SET
                date = "'+CONVERT(VARCHAR(19),dok_kuup,120)+'", 
                total = "'+CAST(kokkusum AS nvarchar)+'",
                number = "'+RTRIM(dok_nr)+'", 
                created = "'+CONVERT(VARCHAR(19),savetime,120)+'", 
                rounded = "'+CAST(ymardus AS nvarchar)+'",
                currency = "'+CAST(valuuta AS nvarchar)+'", 
                due_date = "'+CONVERT(VARCHAR(19),tasupaev,120)+'", 
                pk_joosep = "'+CAST(dok_kood AS nvarchar)+'",
                joosep_hankija = "'+CAST(hankija AS nvarchar)+'";
             UPDATE
                bills, users, companies 
             SET 
                bills.user_id = users.id,
                bills.imported = NOW()
             WHERE
                bills.imported IS NULL
                AND companies.id = users.company_id
                AND companies.pk_joosep = 10
                AND bills.user_id = users.pk_joosep',
            'bills',
            '200'
        FROM inserted
END

每次在'dokument'表中插入一行时,它会在'sync_stack'表中插入一行。 'sql'列将包含一个SQL,用于在另一个(MySQL)数据库中创建相同类型的行。

但是这个触发器无效:

CREATE TRIGGER [dbo].[klient_insert]
   ON [dbo].[klient]
   AFTER INSERT
AS 
BEGIN
    SET NOCOUNT ON;
    INSERT INTO [bcg_ekodu].[dbo].[sync_stack] (event,sql, table_name, import_priority)
        SELECT 
            'INSERT',
            'INSERT INTO users SET
                username =10'+CAST(kl_kood as nvarchar)+',
                password = NULL,
                name ="'+LTRIM(RTRIM(kl_nimi))+'",  
                email ="'+CAST(LTRIM(RTRIM(kl_email)) as nvarchar)+'",  
                reference_no ="'+CAST(LTRIM(RTRIM(kl_viide)) as nvarchar)+'",   
                phone ="'+CAST(LTRIM(RTRIM(kl_tel1)) as nvarchar)+'",   
                logins ="'+CAST(0 as nvarchar)+'",  
                last_login = NULL,  
                created ="'+CONVERT(VARCHAR(19),savetime,120)+'",   
                updated = NULL, 
                deleted ="0",   
                address ="'+CAST(LTRIM(RTRIM(kl_aadr1)) as nvarchar)+'",    
                pk_joosep ="'+CAST(kl_kood as nvarchar)+'"',
            'users',
            '210'
        FROM inserted
END

虽然执行上面的SQL来创建触发器就完成了,但是当我尝试将一些行插入'triggered'表时,我收到以下错误:

No row was updated.

The data in row 175 was not committed.
Error Source: .Net SqlClient Data Provider.
Error Message: Cannot insert the value NULL into column 'sql', table 'mydb.dbo.sync_stack'; column does not allow nulls. INSERT fails.

The statement has been terminated.

Correct the errors and retry or press ESC to cancel the change(s).
  • 如果删除此触发器,则不会发生此错误。
  • 如果我只插入'sql'列的纯文本,它会按预期工作。
  • 如果我使用插入行中的任何字段,即使只是一个文本字段,它也会再次失败。
  • 如果我在'sql'列中允许NULL值,插入行成功但我在'sql'列中得到一个NULL值。

如何让第二个触发按预期工作?

2 个答案:

答案 0 :(得分:8)

我怀疑至少有一个插入到SQL语句中的值是NULL。您可以使用COALESCE来避免这种情况,例如

username =10'+COALESCE(CAST(kl_kood as nvarchar), '')+',

当然,如果没有指定长度,你不应该声明nvarchar,对吗?

答案 1 :(得分:-1)

将任何值连接为NULL为NULL:

select 'test' + NULL

结果为null,您应该为列使用类似的内容:

select isnull(column, '')

这会导致一个空字符串。