2013-07-12 101 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); 
相关问题