1

当用户删除数据库中的一行时,我想将其归档到数据库中的单独表中,而不是在当前表中删除或标记它。我想我需要在这个链接中做类似的事情:

如何将一行从一个 SQL Server 表复制到另一个

问题是,存档表中有 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 以添加原始表中不存在的另一个参数?

4

6 回答 6

2

为什么不在后端处理这个?您可以在原始表上创建触发器以在每次删除后插入另一个表?您的触发器将如下所示:

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

当原始表中的一条记录被删除时,它会将删除的记录插入到另一张表中。您可能想继续阅读此处deleted的表格。

检查这个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;
于 2013-07-12T02:22:31.267 回答
2

好问题。我建议(正如 Gian 也建议的那样)将备份已删除行所需的逻辑移动到删除时触发的触发器中。

触发器是数据库中与表相关联的事件,这些事件在发生操作(即插入/更新/删除)时触发。

因此,在您的场景中,如果您在源表中创建ON DELETE触发器,它将在发生删除时被触发。触发器中包含的 SQL 可以指定如何处理已删除的数据,在您的场景中将是:将已删除的信息插入带有时间戳的存档表中。

因此,如果您有:

Source_Table:
Col_1
Col_2
Col_3

Archive_Table:
Col_1
Col_2
Col_3
Time_Stamp

您需要FOR DELETE针对 Source_Table 创建一个触发器(类似这样):

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,可能包含一些语法错误,但传达了想法的核心。

于 2013-07-12T05:02:45.163 回答
1

您将不得不使用 INSERT 语句的显式列列表和值形式:

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

请参阅插入 ... 值( SELECT ... FROM ... )

于 2013-07-12T02:20:36.317 回答
1

我认为你必须用这样的东西指定列

INSERT INTO tab1
(col1, col2)
SELECT col1, col2
FROM tab2
WHERE  RowID = @rowID"
于 2013-07-12T02:20:45.380 回答
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);
于 2013-07-12T02:21:59.050 回答
0

这是我的建议,您必须提供列名,否则它不会让您运行查询,但是我知道您更喜欢适用于任何表的通用解决方案,因此我建议动态构建插入 SQL,将其缓存在您的应用程序,然后只需使用额外的存档列执行它。这是 ac# 示例:

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);
于 2013-07-12T05:53:18.973 回答