2012-04-17 40 views
3

我必须将在MSSQL中完成的更改与远程MySQL数据库同步。要同步的更改将发票和用户添加到系统中。远程服务器不会总是可以访问,所以我试图建立一种日志表来存储在MSSQL中完成的更改。为什么触发器在使用'插入'表中的字段时尝试插入NULL值?

这里是一个完全正常触发:

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 

,每天一个行插入“库门”表时插入行“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创建触发器执行完成就好了,当我尝试了一些行插入到“触发”表中,我得到的以下错误:

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值。

如何使第二个触发器按预期工作呢?

回答

-1

串联为NULL任何值为NULL:

select 'test' + NULL 

结果无效,你应该使用类似的东西为你列:

select isnull(column, '') 

这将导致一个空字符串。

+0

就是这样!谢谢! – Henno 2012-04-17 22:02:14

+0

我认为你对COALESCE有一个毫无根据的偏见。我在7年前写了这篇文章:http://databases.aspfaq.com/database/coalesce-vs-isnull-sql.html如果你仔细阅读,你会发现COALESCE唯一的性能问题是当一个表达式涉及一个子查询。这个问题不涉及子查询。因此,我认为我的回答是短视的,并没有什么意义 - 你在做大胆的,通用的陈述,但实际上这并不是真的,但毫无疑问的用户会相信,因为你的答案被接受了。丢人现眼。 – 2012-04-18 02:02:53

+2

假设“列”是char(3)(货币代码),并且您希望在NULL时使用“UNKNOWN”。 ISNULL将给予“UNK”。 COALESCE将会给出“UNKNOWN”。ISNULL不是*正确*,你的意思是“永远”。 http://dba.stackexchange.com/a/4277/630 – gbn 2012-04-18 06:45:38

8

我怀疑至少有一个插入到你的SQL语句中的值是NULL。您可以使用COALESCE(例如

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

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

http://sqlblog.com/blogs/aaron_bertrand/archive/2009/10/09/bad-habits-to-kick-declaring-varchar-without-length.aspx

+0

-1当您可以使用isnull – Philipp 2012-04-17 22:02:47

+0

+1指示nvarchar应具有指定的长度以防止将值截断为30个字符时,不应使用COALESCE。我不知道。 – Henno 2012-04-17 22:08:00

+0

@PhilippMehrwald我很抱歉,但ISNULL对于COALESCE有什么优势? COALESCE是ANSI标准,但许多人将ISNULL与VB相关的表弟混淆,后者的工作方式不同。 COALESCE也支持两个以上的参数。那么为什么这是一个-1? – 2012-04-17 23:52:28