Как я могу выполнить MERGE в DbFit?

Я хотел бы убедиться, что справочные таблицы заполнены, прежде чем выполнять тесты для базы данных. Конкретные данные, которые я хочу использовать, могут или не могут быть уже в тестовой базе данных, поэтому я хотел бы выполнить MERGE (также известный как UPSERT), который вставил бы данные, если их еще не было в таблице, и обновил бы это если бы было.

Из того, что я вижу из Google, DbFit, похоже, не поддерживает команду MERGE, а также не поддерживает выполнение SQL, загруженного из внешнего файла сценария SQL (план B состоял в том, чтобы создать MERGE в файле сценария SQL, а затем загрузить файл и запустить его в DbFit).

Есть ли какой-нибудь прямой способ выполнить MERGE в DbFit, или мне нужно будет создать специальный класс фикстур для этого?

1 ответ

Решение

Я понял, как это сделать, используя только стандартные команды из версии FitSharp DbFit.

Этот пример выполняется для базы данных SQL Server. У Oracle аналогичный синтаксис для оператора MERGE, хотя я не знаю, как он обрабатывает временные таблицы. MySQL не имеет оператора MERGE; у него есть нестандартная команда, которая выполняет то же самое. Он также поддерживает временные таблицы, но я не знаком с синтаксисом временных таблиц MySql.

Вот определение целевой таблицы, в которую я хочу объединить данные:

CREATE TABLE Student 
(
    [Name] NVARCHAR(200), 
    DateOfBirth DATETIME, 
    Notes NVARCHAR(1000)
);

Вот страница режима потока DbFit, которая объединит в нее данные:

!| Execute | CREATE TABLE #MergeSource ([Name] NVARCHAR(200), DateOfBirth DATETIME, Notes NVARCHAR(1000)); |

!| Insert | tempdb.dbo.#MergeSource |
| Name       | DateOfBirth | Notes                |
| Jane Smith | 1997-09-24  | These are some notes |
| John Doe   | 2000-04-06  | Other notes          |

!| Execute | !-
MERGE INTO Student AS target
USING 
    (
        SELECT [Name], [DateOfBirth], [Notes]
        FROM #MergeSource
    ) AS source
ON target.[Name] = source.[Name]
WHEN MATCHED THEN
    UPDATE 
    SET [DateOfBirth] = source.[DateOfBirth], 
        [Notes] = source.[Notes]
WHEN NOT MATCHED BY TARGET THEN 
    INSERT ([Name], [DateOfBirth], [Notes])
    VALUES (source.[Name], source.[DateOfBirth], source.[Notes]);
    -! |

!| Query | SELECT [Name], DateOfBirth, Notes FROM Student; |
| Name       | DateOfBirth | Notes                |
| Jane Smith | 1997-09-24  | These are some notes |
| John Doe   | 2000-04-06  | Other notes          |

Сначала создается временная таблица, которая служит источником данных для MERGE. Данные для слияния вставляются во временную таблицу, после чего выполняется оператор MERGE. Команда Query в конце не нужна для MERGE, она была добавлена ​​только для проверки правильности обновления целевой таблицы.

Обратите внимание, что команда Вставка должна использовать имя из трех частей для временной таблицы, по крайней мере, в SQL Server. Когда команда "Вставить" выполняется в отношении SQL Server, за кулисами она запрашивает sys.columns для получения информации о столбцах вставляемой таблицы:

exec sp_executesql N'select c.[name], TYPE_NAME(c.system_type_id) as [Type], c.max_length, 
    0 As is_output, 0 As is_cursor_ref, c.precision, c.scale
    from tempdb. sys.columns c 
    where c.object_id = OBJECT_ID(@objname) 
    order by column_id',
        N'@objname nvarchar(23)',
        @objname=N'tempdb.dbo.#MergeSource'

Функция OBJECT_ID будет возвращать идентификатор объекта временной таблицы, только если имя таблицы задано как имя из трех частей. Это связано с тем, что SQL Server всегда создает временные таблицы в базе данных tempdb, а не в той базе данных, где будет использоваться временная таблица. Функция OBJECT_ID не найдет метаданные для временной таблицы, если ей не предложено искать ее в базе данных tempdb.

Другие вопросы по тегам