Временные таблицы SQL Server - Как мне ввести строку, которая не «сейчас»? - PullRequest
0 голосов
/ 22 октября 2018

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

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

...