2013-07-12 96 views
1

當用戶刪除數據庫中的一行時,我想將其歸檔到數據庫中的單獨表中,而不是將其刪除或在當前表中將其標記。我想我需要在這個環節上做一些事情,如:將一個表中的行復制到另一個SQL中

How to copy a row from one SQL Server table to another

的事情是,存檔表中有1個額外的列不原始表(ArchiveTimeStamp)相匹配。這ArchiveTimeStamp不會在原來的表中,而不是我會使用類似

archiveComm.Parameters.AddWithValue("ArchiveTimeStamp", Date.Time.Now); 

這是我到目前爲止有:

SqlCommand archiveComm = new SqlCommand("INSERT INTO Archive_Table SELECT * FROM Table WHERE RowID = @rowID", conn); 

有沒有辦法讓我修改的SqlCommand添加另一個參數不存在於原始表中?

回答

2

爲什麼不在後端處理呢?您可以在原始表上創建一個觸發器,以在每次刪除後插入另一個表中? 您的觸發器將是這樣的:

CREATE TRIGGER onOriginalTableDelete 
ON originalTable 
FOR DELETE 
AS 
INSERT INTO anotherTable 
SELECT * FROM deleted; 

當記錄原始表中刪除,它會插入刪除的記錄到另一個表。您可能需要閱讀deletedhere

檢查此SQL Fiddle。既然你在另一列中插入時間戳,你可以添加此對INSERT INTO SELECT聲明:

INSERT INTO OtherTable 
SELECT *, CURRENT_TIMESTAMP FROM MainTable; 

這可能是您的觸發查詢:

CREATE TRIGGER onOriginalTableDelete 
ON originalTable 
FOR DELETE 
AS 

INSERT INTO anotherTable 
SELECT *, CURRENT_TIMESTAMP FROM deleted; 
+0

這將是一個存儲過程嗎?調用存儲過程實際上很有意義。但是,如果在另一個表(時間戳)中增加一列,SELECT * FROM將無法正常工作? – Kevin

+1

我不是觸發器的粉絲,但這似乎是一個非常好的使用。 – Matthew

+0

不,這不是一個存儲過程,它是一個觸發器。您不必調用它,當您從表中刪除一條記錄時,它將自動在數據庫中。 –

1

你將不得不使用顯式列列表和值的INSERT語句形式:

INSERT INTO Archive_Table (
    Col1 
    ,Col2 
    ,Col3) 
SELECT 
    Col1 
    ,Col2 
    ,Col3 
FROM 
    Table 
WHERE 
    Row_ID = @Row_ID 

Insert into ... values (SELECT ... FROM ...)

+0

我演這個角色,但我不知道,我會把ArchiveTimeStamp,這是一個列,它是隻在archive_Table中,而不在原始表中。 – Kevin

1

我認爲你必須有這樣的事情

INSERT INTO tab1 
(col1, col2) 
SELECT col1, col2 
FROM tab2 
WHERE RowID = @rowID" 
指定列
1

您需要在該情況下指定列名稱:

archiveComm.Parameters.AddWithValue("ArchiveTimeStamp", Date.Time.Now); 
string SQL = "INSERT INTO Archive_Table (Col1,Col2,ArchiveTimeStamp) " & _ 
       "SELECT Col1,Col2,@ArchiveTimeStamp FROM Table WHERE RowID = @rowID" 
SqlCommand archiveComm = new SqlCommand(SQL, conn); 
+0

如果ArchiveTimeStamp在原始表中不存在,這是否工作?我編輯了我的問題,使其更清晰。我想爲ArchiveTimeStamp使用類似Date.Time.Now的東西(基本上是創建存檔行時的時間戳) – Kevin

+0

在這種情況下,您可以像查看@rowID一樣將值傳遞給查詢。目前的解決方案記錄了在DB中插入記錄的時間。 – NeverHopeless

+0

這種語法將是錯誤的,但有沒有辦法做到這一點,如下所示:SqlCommand archiveComm = new SqlCommand(「INSERT INTO Archive_Table(Col1,Col2,ArchiveTimeStamp)VALUES(SELECT * FROM表WHERE RowID = @rowID,@timeStamp) 「,conn); – Kevin

2

好問題。我建議(正如Gian也建議的那樣)將你需要的邏輯移動到備份被刪除的行到觸發器中,以便在刪除時觸發。

觸發器是一個數據庫中的事件,該數據庫與一個表格相關聯,該表格在發生動作時觸發,即插入/更新/刪除。

因此,在您的方案中,如果您在源表中創建了一個ON DELETE觸發器,則在發生刪除時它將被觸發。觸發器中包含的SQL可以指定如何處理刪除的數據,這將在您的方案中執行:使用時間戳將刪除的信息插入存檔表。

所以,如果您有:

Source_Table: 
Col_1 
Col_2 
Col_3 

Archive_Table: 
Col_1 
Col_2 
Col_3 
Time_Stamp 

你需要創建針對Source_Table一個FOR DELETE觸發(像這樣):

CREATE TRIGGER SourceDeletedTrigger 
ON database.dbo.Source_Table 
FOR DELETE 
AS 

INSERT INTO Archive_Table(Col_1, Col_2, Col_3, Time_Stamp) 
    SELECT 
    DELETED.Col_1, 
    DELETED.Col_2, 
    DELETED.Col_3, 
    GETDATE() 
    FROM DELETED 

GO 

以上是一些粗糙的SQL可能含有幾個語法錯誤,但這個想法的膽量傳達出來。

+0

謝謝!像魅力工作 – Kevin

+0

無後顧之憂。將這種邏輯放入數據庫層總是好的,因爲它應該儘可能獨立於應用程序。 –

0

這是我的建議,你不得不提供列名或它不會讓你運行查詢,但我明白你會喜歡一個通用的解決方案,適用於任何表,所以我建議動態地插入SQL ,將其緩存在您的應用程序上,然後只需使用您的額外存檔列執行即可。這裏是一個C#示例:

public class ArchiveTableRow 
{ 
    private static readonly IDictionary<string, string> _cachedInsertStatements = new Dictionary<string, string>(); 

    public void Archive(string tableName, string rowId) 
    { 
     if (_cachedInsertStatements.ContainsKey(tableName) == false) 
     { 
      BuildInsertStatement(tableName); 
     } 

     var insertQuery = _cachedInsertStatements[tableName]; 

     // ...  
     SqlCommand archiveComm = new SqlCommand(insertQuery, conn); 
     // ...  
     archiveComm.Parameters.AddWithValue("ArchiveTimeStamp", Date.Time.Now);  
     // ...  
    } 

    private void BuildInsertStatement(string tableName) 
    { 
     // Get the columns names: 
     var getColumnNamesQuery = @" 
      SELECT Table_Schema, Column_Name 
      FROM Information_Schema.Columns 
      WHERE Table_Name = '" + tableName + "' 
      Order By Ordinal_Position"; 

     // Execute the query 
     SqlCommand archiveComm = new SqlCommand(getColumnNamesQuery, conn); 

     // Loop and build query and add your archive in the end 

     // Add to dictionary  
    } 
} 

你會喜歡的東西使用它:

var archiveRow = new ArchiveTableRow(); 

archiveRow.Archive("TableName", rowId); 
相關問題