Я работаю в системе, которая будет периодически обрабатывать сообщения из внешнего источника и сохранять результаты в нашей базе данных.В частности, он получает сообщения типа «Пациент X перемещен в местоположение Y в 09:45 утра, 22.10.2008 ...»
В идеале я хотел бы иметь возможность использовать временные таблицы SQL Server.создать исторический след «где был пациент», чтобы я мог запросить, где он находился в определенный момент времени.
-- ============================================================
CREATE TABLE [dbo].[Patients] (
[Id] [int] IDENTITY(1,1) NOT NULL,
CONSTRAINT [PK_Patients] PRIMARY KEY([Id]),
-- Data...
);
-- ============================================================
CREATE TABLE [dbo].[Locations] (
[Id] [int] IDENTITY(1,1) NOT NULL,
CONSTRAINT [PK_Locations] PRIMARY KEY([Id]),
-- Data...
);
-- ============================================================
CREATE TABLE [dbo].[PatientLocations] (
[PatientId] [int] NOT NULL,
CONSTRAINT [PK_PatientLocations] PRIMARY KEY([PatientId]),
CONSTRAINT [FK_PatientLocations_PatientId] FOREIGN KEY([PatientId])
REFERENCES [dbo].[Patients] ([Id]),
[LocationId] [int] NOT NULL,
CONSTRAINT [FK_PatientLocations_LocationId] FOREIGN KEY([LocationId])
REFERENCES [dbo].[Locations] ([Id]),
[DateStartedUtc] datetime2 GENERATED ALWAYS AS ROW START NOT NULL,
[DateEndedUtc] datetime2 GENERATED ALWAYS AS ROW END NOT NULL,
PERIOD FOR SYSTEM_TIME ([DateStartedUtc],[DateEndedUtc])
)
WITH ( SYSTEM_VERSIONING = ON ( HISTORY_TABLE = [dbo].[PatientLocations_History] ) );
Проблема в том, что [DateStartedUtc] можно заполнить толькотекущее системное время, которое не обязательно является временем изменения местоположения пациента.
Мой конкретный вопрос: - Есть ли хороший способ ввода новых данных во временную таблицу, нопометить его с конкретными датами начала?(Должен ли [DateStartedUtc] быть «GENERATED»?) - Если нет, есть ли другие рекомендации по хранению таблицы истории с запросами?
Отредактировано, чтобы добавить: - напомнил мне Аарон вкомментарии для упоминания о выключении и включении системы контроля версий.Одно из возможных решений, которое я исследовал, состояло бы в том, чтобы отключить управление версиями системы, вставить новую строку в dbo.PatientLocations или dbo.PatientLocations_History и снова включить управление версиями системы (все в рамках транзакции).Я не думаю, что это хорошее решение для регулярных обновлений таблицы (и это потребовало бы от меня ручного ведения дат начала и окончания), но я открыт для убеждения.
ДополнительноОбновления
Чтобы добавить больше контекста, мое первоначальное решение (до того, как я обнаружил временные таблицы) состояло в том, чтобы поддерживать одну таблицу истории с триггером:
-- ============================================================
CREATE TABLE [dbo].[Patients] (
[Id] [int] IDENTITY(1,1) NOT NULL,
CONSTRAINT [PK_Patients] PRIMARY KEY([Id]),
-- Data...
);
-- ============================================================
CREATE TABLE [dbo].[Locations] (
[Id] [int] IDENTITY(1,1) NOT NULL,
CONSTRAINT [PK_Locations] PRIMARY KEY([Id]),
-- Data...
);
-- ============================================================
CREATE TABLE [dbo].[PatientLocations] (
[Id] [int] IDENTITY(1,1) NOT NULL,
CONSTRAINT [PK_PatientLocations] PRIMARY KEY ([Id]),
[PatientId] [int] NOT NULL,
CONSTRAINT [FK_PatientLocations_PatientId] FOREIGN KEY([PatientId])
REFERENCES [dbo].[Patients] ([Id]),
[LocationId] [int] NOT NULL,
CONSTRAINT [FK_PatientLocations_LocationId] FOREIGN KEY([LocationId])
REFERENCES [dbo].[Locations] ([Id]),
-- Timestamps
[LocationStartedAtDateOffset] [datetimeoffset] NOT NULL,
[_LocationCompletedAtDateOffset] [datetimeoffset] NULL,
);
GO
-- ================================================================================
CREATE TRIGGER [dbo].[TRG_PatientLocations_LocationCompletedAtDateOffset]
ON [dbo].[PatientLocations]
AFTER UPDATE, INSERT, DELETE
AS
BEGIN
WITH
-- ========================================
[ModifiedPatientIds] AS (
SELECT DISTINCT [PatientId]
FROM (
SELECT [PatientId] FROM inserted
UNION SELECT [PatientId] FROM deleted
) p
),
-- ========================================
[PList] AS (
SELECT
p.[Id],
p.[PatientId],
p.[LocationStartedAtDateOffset],
LEAD(p.[LocationStartedAtDateOffset], 1)
OVER(PARTITION BY p.[PatientId] ORDER BY p.[LocationStartedAtDateOffset])
AS [LocationCompletedAtDateOffset]
FROM [dbo].[PatientLocations] p
JOIN [ModifiedPatientIds] mp ON p.[PatientId] = mp.[PatientId]
)
-- ========================================
UPDATE p SET
p.[_LocationCompletedAtDateOffset] = pl.[LocationCompletedAtDateOffset]
FROM [dbo].[PatientLocations] p
JOIN [PList] pl ON p.[Id] = pl.[Id]
END;
GO
Я изначально отошелИсходя из этого решения, поскольку триггеры обычно работают плохо.
I думал Временные таблицы решат мою проблему элегантно, но, как уже упоминалось в комментариях, они действительно предназначены только для системного управления версиями, а не для пользователей.определенное управление версиями.
Итак, мой измененный вопрос: - Каков наилучший способ хранения и ведения пользовательской истории в базе данных?- Есть ли лучшее решение, чем использование триггеров?Или есть более эффективный способ использования триггеров?