2012-04-17 22 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