正在SQL中将行从1个表复制到另一个表
本文关键字:复制 另一个 1个 SQL 正在 | 更新日期: 2023-09-27 18:21:59
当用户删除数据库中的一行时,我希望将其归档到数据库中的单独表中,而不是在当前表中删除或标记它。我想我需要在这个链接中做一些类似的事情:
如何将一行从一个SQL Server表复制到另一个
问题是,存档表中有一个额外的列,与原始表(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以添加原始表中不存在的另一个参数?
为什么不在后端处理这个问题?您可以在原始表上创建一个触发器,以便在每次删除后插入到另一个表中吗?您的触发器将如下所示:
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;
好问题。我建议(正如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,其中可能包含一些语法错误,但传达了想法的核心。
您必须使用INSERT语句的显式列列表和值形式:
INSERT INTO Archive_Table (
Col1
,Col2
,Col3 )
SELECT
Col1
,Col2
,Col3
FROM
Table
WHERE
Row_ID = @Row_ID
请参阅插入。。。值(SELECT…FROM…)
我认为您必须用类似的东西来指定列
INSERT INTO tab1
(col1, col2)
SELECT col1, col2
FROM tab2
WHERE RowID = @rowID"
在这种情况下,您需要指定列名:
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);
这是我的建议,你必须提供列名,否则它不会让你运行查询,但我知道你更喜欢适用于任何表的通用解决方案,所以我建议动态构建insert 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);