2012-07-17 65 views
0

我試圖創建一個MySQL之前插入觸發器與下面的代碼,它會做我想做的事情,如果我能找到一種方法來執行準備好的語句生成的觸發。替代在觸發器中使用Prepared Statement與MySQL

是否有任何替代方法從觸發器內執行預準備語句?感謝

BEGIN 
    SET @CrntRcrd = (SELECT AUTO_INCREMENT FROM information_schema.TABLES 
       WHERE TABLE_SCHEMA=DATABASE() 
       AND TABLE_NAME='core_Test'); 

    SET @PrevRcrd = @CrntRcrd-1; 

    IF (NEW.ID IS NULL) THEN 
     SET NEW.ID = @CrntRcrd; 
    END IF; 

    SET @PrevHash = (SELECT Hash FROM core_Test WHERE [email protected]); 

    SET @ClmNms = (SELECT CONCAT('NEW.',GROUP_CONCAT(column_name 
        ORDER BY ORDINAL_POSITION SEPARATOR ',NEW.'),'') 
        FROM information_schema.columns 
        WHERE table_schema = DATABASE() 
        AND table_name = 'core_Test'); 

    SET @Query = CONCAT("SET @Query2 = CONCAT_WS(',','",@PrevHash,"','", @CrntRcrd, "',", @ClmNms, ");"); 

    PREPARE stmt1 FROM @Query; 
    EXECUTE stmt1; 
    DEALLOCATE PREPARE stmt1; 

    SET NEW.Hash = @Query2; 
END 

UPDATE /澄清:的數據將被存儲在表中,如下。

+------------+-----+------+----------------+ 
| Record (AI)| ID | Data | HASH   | 
+------------+-----+------+----------------+ 
| 1   | 1 | ASDF | =DHFBGKJSDFHBG | (Hash Col 1) 
| 2   | 2 | NULL | =UEGFRYJKSDFHB | (Hash Col 1 + Col 2) 
| 3   | 1 | VBNM | =VKJSZDFVHBFJH | (Hash Col 2 + Col 3) 
| 4   | 4 | TYUI | =KDJFGNJBHMNVB | (Hash Col 3 + Col 4) 
| 5   | 5 | ZXCV | =SDKVBCVJHBJHB | (Hash Col 4 + Col 5) 
+------------+-----+------+----------------+ 

在每個插入命令表將通過透水行的哈希值appeding到整個新行的CONCAT()生成該行的哈希值,然後重新散列整個字符串。這將創建一個哈希值的運行記錄,以用於審計目的/在應用程序的另一部分中使用。

我的約束是,這必須在INSERT之前完成,因爲之後不能更新行。

UPDATE:我目前使用下面的代碼,直到我能找到一種方法,通過列名動態CONCAT:

BEGIN 

    SET @Record = (
    SELECT AUTO_INCREMENT FROM information_schema.TABLES 
    WHERE TABLE_SCHEMA=DATABASE() 
    AND TABLE_NAME='core_Test' #<--- UPDATE TABLE_NAME HERE 
); 
    SET @PrevRecrd = @Record-1; 

    IF (new.ID IS NULL) THEN 
    SET new.ID = @Record; 
    END IF; 

    SET @PrevHash = (
    SELECT Hash FROM core_Test #<--- UPDATE TABLE_NAME HERE 
    WHERE [email protected] 
); 

    SET new.Hash = SHA1(CONCAT_WS(',',@PrevHash, @Record, 
    /* --- UPDATE TABLE COLUMN NAMES HERE (EXCLUDE "new.Record" AND "new.Hash") --- */ 
    new.ID, new.Name, new.Data 
)); 

END 

回答

1

簡短的回答是,你不能使用動態SQL在TRIGGER中。

我對auto_increment值的查詢感到困惑,併爲ID列指定一個值。我不明白你爲什麼需要設置ID列的值。是不是被定義爲AUTO_INCREMENT的列?數據庫將處理分配。

目前還不清楚您的查詢是否保證返回唯一值,特別是在併發插入運行時。 (我沒有測試,所以它可能工作。)

但代碼是奇特的。

它看起來好像你想要完成的是從最近插入的行中獲取列的值。我認爲在查詢觸發器定義的同一個表時有一些限制。 (我知道肯定有是Oracle,MySQL可能會更寬鬆。)

如果我需要做這樣的事情,我會嘗試這樣的事:

SELECT @prev_hash := t.hash AS prev_hash 
    FROM core_Test t 
    ORDER BY t.ID DESC LIMIT 1; 

SET NEW.hash = @prev_hash; 

但同樣,我不知道這會工作(我需要測試)。如果它適用於一個簡單的案例,那麼並不能證明它在所有的時間都是有效的,在併發插入的情況下,在擴展插入的情況下,等等。

我按照我所做的方式編寫了查詢,以便它可以使用ID列上的索引來執行反向掃描操作。如果不使用索引,我會嘗試重寫該查詢(可能爲連接,以獲得最佳的性能。從MySQL 5.1參考手冊
E.

SELECT @prev_hash := t.hash AS prev_hash 
    FROM (SELECT r.ID FROM core_Test r ORDER BY r.ID DESC LIMIT 1) s 
    JOIN core_Test t 
    ON t.ID = s.ID 

摘錄上存儲程序1個限制
<剪斷>
SQL語句製備(準備,執行DEALLOCATE PREPARE)可以在存儲過程中使用,但不存儲功能或觸發器。因此,存儲函數和觸發器不能使用動態SQL(在這裏您構建語句字符串,然後執行它們)。
< /剪斷>