Временные таблицы SQL Server - Как мне ввести строку, которая не "сейчас"?

Я работаю над системой, которая будет периодически обрабатывать сообщения из внешнего источника и сохранять результаты в нашей базе данных. В частности, он получает сообщения типа "Пациент X переехал в пункт Y в 9:45 утра, 22 октября 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

Я изначально отошел от этого решения, так как триггеры обычно работают плохо.

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

Итак, мой измененный вопрос: - Каков наилучший способ хранить и поддерживать пользовательскую историю в базе данных? - Есть ли лучшее решение, чем использование триггеров? Или есть более эффективный способ использования триггеров?

0 ответов

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