SQL Сервер: обновить существующую запись и вставить новую запись - PullRequest
0 голосов
/ 10 июля 2020

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

Текущий результат:

+---------------------+------------------+------------------+------------------+
|         Name        |    Department    |    Start Date    |     End Date     |
+---------------------+------------------+------------------+------------------+
|         Tom         |     Finance      |    2010-08-09    |   9999-12-31     | 
+---------------------+------------------+------------------+------------------+

Желаемый результат

+---------------------+------------------+------------------+------------------+
|         Name        |    Department    |    Start Date    |     End Date     |
+---------------------+------------------+------------------+------------------+
|         Tom         |     Finance      |    2010-08-09    |   2010-10-10     |
|         Tom         |        HR        |    2010-10-11    |   9999-12-31     | 
+---------------------+------------------+------------------+------------------+

В настоящее время я беру существующие записи и сохраняю их во временную таблицу. Затем я выполняю присоединение нескольких полей к существующей таблице, чтобы увидеть, существовал ли этот человек раньше. Если человек существует, я продолжаю сохранять данные во временную таблицу и выполнять обновления, прежде чем вернуться и обновить основную таблицу. Мне это решение не нравится, и оно очень запутанное. Есть ли лучшее решение для решения указанной выше проблемы?

1 Ответ

0 голосов
/ 10 июля 2020

РЕДАКТИРОВАТЬ. Поскольку хранимая процедура уже существует, вы можете встроить аналогичный logi c в SP. Я создал образец хранимой процедуры, которая будет принимать имя сотрудника, обновлять отдел, а затем реализовывать вашу бизнес-логику c. Опять же, укажите в качестве параметра истинное поле первичного ключа (а не имя сотрудника), иначе вы можете обновить несколько записей.

ALTER PROCEDURE UpdateDepartment @EmpName VARCHAR(20), @Dept VARCHAR(20)
AS
BEGIN
    DECLARE @Changed TABLE
    (
        EmpName VARCHAR(20),
        OldDepartment VARCHAR(20),
        NewDepartment VARCHAR(20),
        StartDate DATETIME2,
        EndDate DATETIME2
    )

    UPDATE TempEmployees
    SET
        Department = @Dept
    output 
        inserted.EmpName, 
        deleted.Department, 
        inserted.Department, 
        inserted.StartDate,
        inserted.EndDate
    into @Changed
    WHERE EmpName = @EmpName

    DECLARE @OldDept VARCHAR(20);

    SELECT @OldDept = OldDepartment FROM @Changed

    UPDATE TempEmployees 
    SET 
        EndDate = CURRENT_TIMESTAMP,
        Department = @OldDept
    WHERE EmpName = @EmpName;

    INSERT INTO TempEmployees 
    SELECT
        EmpName,
        NewDepartment,
        DATEADD(DAY, 1, CURRENT_TIMESTAMP),
        '99991231'
    FROM @Changed

END

Один из вариантов - использовать триггер и использовать выходные таблицы, которые генерируются оператором UPDATE. Когда выполняется инструкция UPDATE, генерируются выходные таблицы inserted и deleted с подробным описанием состояния записи до и после.

См. Приведенный ниже код и попробуйте изменить его для ваше приложение. Обратите внимание, что текущая версия триггера использует имя сотрудника как часть предиката для обновлений. Если у вас есть более одной записи для указанного c имени сотрудника, они все будут обновлены. Таким образом, имеет смысл использовать истинное поле первичного ключа в таблице, гарантируя, что только обновляется одна запись.

CREATE TRIGGER TempEmployeeMovedDepartment
ON TempEmployees
AFTER UPDATE 
AS
BEGIN
    SET NOCOUNT ON;

    IF UPDATE(Department)
    BEGIN
        --Update the End Date for the Current Record. In this case, I'm using the EmpName
        --field to denote the record to update. Presumably, you'd have an actual Primary Key
        DECLARE @PK VARCHAR(20);
        DECLARE @OldDept VARCHAR(20);

        SELECT @PK = EmpName, @OldDept = Department FROM deleted;

        UPDATE TempEmployees 
        SET 
            EndDate = CURRENT_TIMESTAMP,
            Department = @OldDept
        WHERE EmpName = @PK;

        INSERT INTO TempEmployees 
        SELECT
            EmpName,
            Department,
            DATEADD(DAY, 1, CURRENT_TIMESTAMP),
            '99991231'
        FROM inserted
    END
END
...