Передать имя таблицы INSERT INTO имя таблицы извне или переменную? - PullRequest
1 голос
/ 23 октября 2019

У меня есть больше таблиц с большим количеством записей в рабочей среде, которые я хочу переместить в базу данных истории.

Я пытался использовать этот запрос, который работает нормально, но я не знаю, есть ли возможностьдать имя столам со стороны. Я не хочу писать этот запрос для каждой базы данных и таблицы.

INSERT INTO [database.history].dbo.tablename
SELECT *
FROM [database.live].dbo.table

DELETE FROM [database.history].dbo.tablename

Я хочу дать имена баз данных и таблиц извне. Я использую щегольскую ORM. Есть ли решение использовать что-то похожее на другие типы? Например.

DECLARE @ProductionTableName nvarchar(250) = '[database.live].dbo.table'

Мои базы данных находятся на одном сервере.

Мои запросы находятся в файлах, и мой вызов выглядит примерно так.

string query = queryFile;
var param = new {Parameter1= stringValue};
var result = Connection.Query<long>(query, param);

Ответы [ 2 ]

2 голосов
/ 23 октября 2019

Нельзя параметризировать идентификаторы в SQL. То, что вы можете сделать, это использовать динамический SQL.
Обратите внимание, однако, что использование динамического SQL может быть опасным, если все сделано неправильно.

Основное правило на самом деле очень простое - вы должны параметризовать то, что вы можете, и занести в белый список то, что вы не можете.
Подробнее читайте в моем блоге Что можно и чего нельзя делатьдинамического SQL для SQL Server.

Кроме того, поскольку вы перемещаете записи из одной таблицы в другую, вам следует использовать транзакцию, в противном случае, если ваш оператор delete завершится неудачно с ошибкой, оператор вставкине будет отменен, и вы получите строки, которые находятся в обеих базах данных.
Для получения дополнительной информации прочитайте Общие сведения о транзакциях между базами данных в SQL Server на red-gate.

Обратите внимание, что если база данных истории находится на другом сервере, чем действующая база данных, вам потребуется распределенная транзакция .

Рабочий пример будет выглядеть примерно так:

DECLARE @TableName sysname = 'TableName',
        @LineBreak nchar(2) = NCHAR(13) + NCHAR(10),
        @Sql nvarchar(4000);

IF EXISTS(
    SELECT 1 
    FROM [database.live].Information_schema.Tables
    WHERE Table_Name = @TableName
)
BEGIN

    SET @SQL = 'BEGIN TRANSACTION' + @LineBreak + 
    'BEGIN TRY' + @LineBreak + 
    'INSERT INTO [database.history].dbo.' + @TableName + @LineBreak + 
    'SELECT *' + @LineBreak + 
    'FROM [database.live].dbo.' + @TableName + @LineBreak +

    'DELETE FROM [database.history].dbo.' + @TableName + 
    'COMMIT TRANSACTION' + @LineBreak + 
    'END TRY' + @LineBreak + 
    'BEGIN CATCH' + @LineBreak + 
    'IF @@TRANCOUNT > 0' + @LineBreak + 
    '    ROLLBACK TRANSACTION' + @LineBreak + 
    'END CATCH' + @LineBreak

    -- When working with dynamic SQL, Print is your best friend.
    PRINT @SQL
    -- Once you've verified that the SQL looks ok, you can unremark the EXEC statemet.
    --EXEC sp_ExecuteSql @SQL
END

Обратите внимание, однако, что считается плохой практикой использовать оператор insert без указания списка столбцов, а также select *.
TЧтобы добавить это к вашему запросу, вы можете запросить sys.columns, чтобы получить столбцы таблицы, которую вы хотите.

Я также заметил, что в коде вопроса нет предложения where - это означает, что все содержимое строки будет перемещено из действующей базы данных в базу данных истории.

1 голос
/ 23 октября 2019

Если вы используете Dapper, это означает, что вы используете запросы в коде c #, а не в хранимых процедурах. Вы можете добавить свой ProdDb и HistoryDb в ваш app.config и использовать его оттуда.

edit: Вы также можете создавать разные строки подключения для обеих БД и открывать любое соединение, которое хотите использовать в своем коде.

Если ваши базы данных находятся на одном и том же сервере, вы можете использовать функцию Репликация SQL Server для репликации рабочей БД в историческую БД.

...