Как создать запрос, который получает только данные, которые были обновлены в таблице

117
14

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


Чтобы показать пример того, что я пытаюсь сделать, я создал хранимую процедуру, которая ОБНОВЛЯЕТ или ВСТАВЛЯЕТ новые записи в локальной таблице, получая записи из таблицы ссылок. Хранимая процедура выполняется как задание в SQL Server для обновления и вставки новых записей.


Мой вопрос: есть ли способ запросить данные в локальной таблице, чтобы изначально я мог получить все записи, а не получать только новые записи, которые были вставлены, или старые обновленные записи?


Я не хочу постоянно получать все записи, добавлять новые записи или обновлять записи.


Возможно ли это?


Вот хранимая процедура, которую я создал в качестве примера для обновления данных локального телефона:


CREATE PROCEDURE sp_UPDATE_PHONE_RECORDS
AS
BEGIN
MERGE dbo.PHONE_REC AS Target
USING (SELECT MEMBER_ID
,HOME_PHONE = dbo.udf_StdPhoneFmt(HOME)
,CELL_PHONE = dbo.udf_StdPhoneFmt(CELL)
,WORK_PHONE = dbo.udf_StdPhoneFmt(WORK)

FROM PHONE WHERE MEMBER_ID IS NOT NULL) AS SOURCE

ON (Target.MEMBER_ID = SOURCE.MEMBER_ID)

WHEN MATCHED THEN

UPDATE SET Target.HOME_PHONE = Source.HOME_PHONE,Target.CELL_PHONE = Source.CELL_PHONE,
Target.WORK_PHONE = Source.WORK_PHONE

WHEN NOT MATCHED BY TARGET THEN
INSERT (MEMBER_ID, HOME_PHONE, CELL_PHONE ,WORK_PHONE)

VALUES (Source.MEMBER_ID, Source.HOME_PHONE, Source.CELL_PHONE, Source.WORK_PHONE);
END
GO


Возможно ли это?


Спасибо всем!

спросил(а) 2012-05-01T00:45:00+04:00 8 лет, 7 месяцев назад
1
Решение
109

Это в основном вариант ответа RDotLee, но это альтернативный подход, который я иногда использую, когда мне не нужна фактическая дата/время, когда записи были созданы:


Я просто добавляю одно поле bit под названием modified со значением по умолчанию 1.

Если в таблицу вставлена ​​новая строка, modified автоматически устанавливается в 1.

Если существующая строка обновлена, я должен убедиться, что для параметра modified установлено значение 1.


Таким образом, задание нужно искать только все строки с modified = 1.

Нет необходимости отслеживать дату/время, когда работа была выполнена в последний раз.


Когда задание выполнено успешно, последнее, что он делает, это "сброс" поля modified во всех строках:


update TheTable set modified = 0

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


Но он имеет тот же недостаток, что и подход RDotLee "LastModifiedOn/CreatedOn" - вам нужно убедиться, что каждое обновление в таблице действительно устанавливает столбец modified равным 1, поэтому вы можете использовать его только тогда, когда вы в управлении всем кодом, который записывается в таблицу.

ответил(а) 2012-05-01T13:30:00+04:00 8 лет, 7 месяцев назад
110

Обычно мы добавляем два поля даты/времени в исходную таблицу, например Source.LastModifiedOn и Source.CreatedOn.


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

Конечно, вы должны быть уверены, что Source.LastModifiedOn и Source.CreatedOn настроены правильно.

ответил(а) 2012-05-01T00:56:00+04:00 8 лет, 7 месяцев назад
92

Я бы использовал предложение OUTPUT с столбцом $action:


DECLARE @Target TABLE
(
Id INT NOT NULL,
Value VARCHAR(10) NULL
);
INSERT @Target
VALUES (1, 'A'), (2, NULL), (3, NULL);
DECLARE @Source TABLE
(
Id INT NOT NULL,
Value VARCHAR(10) NULL
);
INSERT @Source
VALUES (2, 'B'), (4, 'D'), (5, 'E');
DECLARE @AffectedRows TABLE
(
MergeAction NVARCHAR(10) NOT NULL,
Old_Id INT NULL,
Old_Value VARCHAR(10) NULL,
New_Id INT NULL,
New_Value VARCHAR(10) NULL
);

MERGE @Target t
USING @Source s ON t.Id = s.Id
WHEN MATCHED THEN
UPDATE SET Value = s.Value
WHEN NOT MATCHED THEN
INSERT (Id, Value) VALUES (s.Id, s.Value)
OUTPUT $action, deleted.Id, deleted.Value, inserted.Id, inserted.Value
INTO @AffectedRows(MergeAction, Old_Id, Old_Value, New_Id, New_Value);

SELECT * FROM @Target;
SELECT * FROM @AffectedRows;

Результаты:


Id Value
-- -----
1 A
2 B <-- updated row
3 NULL
4 D <-- inserted row
5 E <-- inserted row

MergeAction Old_Id Old_Value New_Id New_Value
----------- ----------- ---------- ----------- ---------
INSERT NULL NULL 4 D
INSERT NULL NULL 5 E
UPDATE 2 NULL 2 B

ответил(а) 2012-05-01T01:27:00+04:00 8 лет, 7 месяцев назад
42

TimeStamp


TimeStamp увеличивается и вставляет или обновляет.


На Мастер сделать это TimeStamp и на Slave сделать его двоичный (8)


select [timeStampSlave].* 
from [timeStampSlave]
join [timeStampMaster]
on [timeStampSlave].[ID] = [timeStampMaster].ID
and [timeStampSlave].[timeStamp] < [timeStampMaster].[timestamp]

Для запросов по серверам вы можете использовать следующий синтаксис


[MasterSever].[test].[dbo].[timeStampMaster]

ответил(а) 2012-05-01T18:58:00+04:00 8 лет, 6 месяцев назад
42

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

ответил(а) 2012-05-01T12:41:00+04:00 8 лет, 7 месяцев назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема