2013-07-12 2 views
1

Когда пользователь удаляет строку в базе данных, я хочу ее закрепить в отдельной таблице в базе данных, а не удалить ее или пометить в текущей таблице. Я полагаю, что мне нужно сделать что-то, как в этой ссылке:Копирование строки из 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 не существует в исходной таблице? Я изменил свой вопрос, чтобы сделать его более ясным. Я хочу использовать что-то вроде Date.Time.Now для ArchiveTimeStamp (в основном это отметка времени, когда была создана строка архива). – Kevin

+0

В этом случае вы можете передать значение для запроса так же, как и для @rowID. В настоящее время решение записывает время, когда запись была вставлена ​​в БД. – NeverHopeless

+0

Этот синтаксис будет неправильным, но есть ли способ сделать это так: SqlCommand archiveComm = new SqlCommand ("INSERT INTO Archive_Table (Col1, Col2, ArchiveTimeStamp) VALUES (SELECT * FROM Table 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 

Вам нужно создать 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, которые могут содержать пара синтаксических ошибок, но передаются идеи.

+0

Спасибо! работал как шарм – Kevin

+0

Не беспокойтесь. Всегда полезно вставлять эту логику в уровень базы данных, поскольку она должна быть независимой от приложения, где это возможно. –

0

Вот мое предложение, вы вынуждены указывать имена столбцов или не разрешаете запускать запрос, однако я понимаю, что вы предпочтете универсальное решение, работающее для любой таблицы, поэтому я предлагаю строить динамическую вставку SQL динамически , кешируйте его в своем приложении, а затем просто выполните его со своим дополнительным столбцом архива. Вот переменный ток # пример:

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); 
Смежные вопросы