7

我不知道从哪里开始或者这将如何工作,我希望有人有一个想法或一个行之有效的方法。

为了展示我正在尝试做的事情的示例,我创建了一个存储过程,它通过从链接表中获取记录来更新或插入本地表中的新记录。存储过程在 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

这可能吗?

感谢大家!

4

5 回答 5

6

我们通常会在源表中添加两个日期/时间字段,例如 Source.LastModifiedOn 和 Source.CreatedOn。

然后,当作业运行以更新目标表时,您可以说让我获得自上次作业运行以来的所有 Source.LastModifiedOn 和 Source.CreatedOn 行,并根据这些行进行更新/插入。

当然,您需要确保 Source.LastModifiedOn 和 Source.CreatedOn 设置正确。

于 2012-04-30T21:56:13.550 回答
4

我会在列中使用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-04-30T22:27:54.990 回答
0

您可以在本地表上编写一个触发器,该触发器将在对其进行更新或插入时触发。作为触发逻辑的一部分,您必须将那些更新或新插入的记录插入到临时表中。这是您可以记录对本地表的更改的最简单方法。

于 2012-05-01T09:41:42.740 回答
0

时间戳

TimeStamp 在插入或更新时递增。

在 Master 上将其设为 TimeStamp,在 Slave 上将其设为 Binary(8)

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

要跨服务器查询,您可以使用以下语法

[MasterSever].[test].[dbo].[timeStampMaster]
于 2012-05-01T15:58:28.033 回答
0

这基本上是RDotLee 答案的变体,但这是我有时在不关心创建记录的实际日期/时间时使用的另一种方法:

我只是添加一个bit名为modified默认值 1的字段。
如果将新行插入表中,modified则自动设置为 1。
如果更新了现有行,我必须确保它modified也设置为 1。

这样,作业只需要搜索所有带有modified = 1.
无需跟踪上次执行作业的日期/时间。

当作业成功执行时,它做的最后一件事是“重置”modified所有行中的字段:

update TheTable set modified = 0

IMO,当您只关心自上次作业运行以来修改了行而不是修改它们时,这种方法工作量较少

但它与 RDotLee 的“LastModifiedOn/CreatedOn”方法具有相同的缺点 - 您需要确保表上的每个更新都确实将modified列设置为 1,因此您只能在控制所有代码时使用它写入表。

于 2012-05-01T10:30:42.233 回答