2017-08-10 31 views
0

为更新操作设置Follying CDC结果集。只有area字段已更新。 enter image description here使用CDC或带有CDC的T-SQL跟踪对字段的更改

在前面sreenshot只包含在表中的部分gields。领域更多。时间到了,他们中的一些人更新了一些没有。在下面的查询中,我尝试通过可用视图中的字段来显示更改的统计信息。查询

with History AS (
SELECT 
cz.GUID as Id, 
cz.category, 
isnull(cz.area, 0) as area, 
isnull(cz.oilwidthmin,0) as oilwidthmin, 
isnull(cz.oilwidthmax,0) as oilwidthmax, 
isnull(cz.efectivwidthmin,0) as efectivwidthmin, 
isnull(cz.efectivwidthmax,0) as efectivwidthmax, 
isnull(cz.koafporistmin,0) as koafporistmin, 
isnull(cz.koafporistmax,0) as koafporistmax, 
CASE cz.__$operation 
WHEN 1 THEN 'DELETE' 
WHEN 2 THEN 'INSERT' 
WHEN 3 THEN 'Before UPDATE' 
WHEN 4 THEN 'After UPDATE' 
END operation, 
map.tran_begin_time as beginT, 
map.tran_end_time as endT 
FROM cdc.fn_cdc_get_all_changes_dbo_EXT_GeolObject_KategZalezh(sys.fn_cdc_get_min_lsn('dbo_EXT_GeolObject_KategZalezh'), sys.fn_cdc_get_max_lsn(), 'all') AS cz 
INNER JOIN [cdc].[lsn_time_mapping] map 
    ON cz.[__$start_lsn] = map.start_lsn 
) 
SELECT field, val, operation, beginT, endT FROM History 
unpivot ([val] for field in 
(
--category, 
area, 
oilwidthmin, 
oilwidthmax, 
efectivwidthmin, 
efectivwidthmax, 
koafporistmin, 
koafporistmax))t where id = '2D166098-7CBD-4622-9EB0-000070506FE6' 

结果是以下几点: enter image description here

但以前的结果中包含额外的数据。 预期结果必须如下: enter image description here

我知道CDC按行跟踪更改。或者,也许我错了?如果不是,我如何在SQL中为val字段做一些比较器。我对t-sql没有深入的了解,我脑子里想到的所有东西都被游标以某种方式使用。有任何想法吗? 也许某种程度上使用CT(更改跟踪)?也许不知何故使用group by

几乎正确的答案。如下因素查询返回预期的结果:

WITH History AS (
    SELECT 
     *, 
     CASE cz.__$operation 
      WHEN 1 THEN 'DELETE' 
      WHEN 2 THEN 'INSERT' 
      WHEN 3 THEN 'Before UPDATE' 
      WHEN 4 THEN 'After UPDATE' 
      END operation, 
     map.tran_begin_time as beginT, 
     map.tran_end_time as endT 
    FROM cdc.fn_cdc_get_all_changes_dbo_EXT_GeolObject_KategZalezh(sys.fn_cdc_get_min_lsn('dbo_EXT_GeolObject_KategZalezh'), sys.fn_cdc_get_max_lsn(), 'all') AS cz 
     INNER JOIN [cdc].[lsn_time_mapping] map 
      ON cz.[__$start_lsn] = map.start_lsn 
    where cz.GUID = '2D166098-7CBD-4622-9EB0-000070506FE6' 
), 
UnpivotedValues AS(
    SELECT guid, field, val, operation, beginT, endT 
    FROM History 
     UNPIVOT ([val] FOR field IN 
     (
      area, 
      oilwidthmin, 
      oilwidthmax, 
      efectivwidthmin, 
      efectivwidthmax, 
      koafporistmin, 
      koafporistmax 
     ))t 
), 
UnpivotedWithLastValue AS (
    SELECT 
     *, 
     --Use LAG() to get the last value for the same field 
     LAG(val, 1) OVER (PARTITION BY field ORDER BY BeginT) LastVal 
    FROM UnpivotedValues 
) 
--Filter out record where the value equals the last value for the same field 
SELECT * FROM UnpivotedWithLastValue WHERE val <> LastVal OR LastVal IS NULL ORDER BY guid 

结果这个查询看起来是这样的: enter image description here

但是,如果使用多个GUID的查询时WHERE cz.GUID =不存在或WHERE谓我得到如下因素的结果:

enter image description here 此结果为两个GUID。在第一行价值LastVal必须是16691.像val从第4行

回答

1

您不能将CDC设置为仅跟踪已更改列的值。但是,您可以很容易地筛选出查询中未改变的值。

考虑下面的查询,这是你的原始查询的简化副本:

WITH History AS (
    SELECT 
     *, 
     CASE cz.__$operation 
      WHEN 1 THEN 'DELETE' 
      WHEN 2 THEN 'INSERT' 
      WHEN 3 THEN 'Before UPDATE' 
      WHEN 4 THEN 'After UPDATE' 
      END operation, 
     map.tran_begin_time as beginT, 
     map.tran_end_time as endT 
    FROM cdc.fn_cdc_get_all_changes_Dbo_YourTable(sys.fn_cdc_get_min_lsn('Dbo_YourTable'), sys.fn_cdc_get_max_lsn(), 'all') AS cz 
     INNER JOIN [cdc].[lsn_time_mapping] map 
      ON cz.[__$start_lsn] = map.start_lsn 
), 
UnpivotedValues AS(
    SELECT id, field, val, operation, beginT, endT, t.tran_id 
    FROM History 
     UNPIVOT ([val] FOR field IN 
     (Column1, Column2, Column3))t 
), 
UnpivotedWithLastValue AS (
    SELECT 
     *, 
     --Use LAG() to get the last value for the same field 
     LAG(val, 1) OVER (PARTITION BY id, field ORDER BY BeginT) LastVal 
    FROM UnpivotedValues 
) 
--Filter out record where the value equals the last value for the same field 
SELECT * FROM UnpivotedWithLastValue WHERE val <> LastVal OR LastVal IS NULL 
ORDER BY Id, beginT 

在此查询我已经使用了LAG()函数来获取每个字段的最后一个值。根据此值,可以过滤掉最终查询中未更改的记录,并在上面显示。

+0

如果在'WITH历史AS('使用'where cz.id ='some ID'')中,您的示例工作正常,在这种情况下,导致'LastVal'与真实值相对应,但如果'where'包含多个id或'where'不存在,那么'LastVal'的值会混合使用 – Seva

+0

你在使用cz.id的列是什么?这很难回答没有数据样本 – dybzon

+0

对不起,请看看,我补充了我的查询 – Seva

0

在你的情况,你可以使用ROW_NUMBER函数顺序号的变化 - 在此之后,你可以加入与前一个每个顺序的变化(基于字段和id)并仅输出具有不同值的行。

事情是这样的:

WITH 
History AS 
(
SELECT 
    cz.GUID as Id, 
    cz.category, 
    isnull(cz.area, 0) as area, 
    isnull(cz.oilwidthmin,0) as oilwidthmin, 
    isnull(cz.oilwidthmax,0) as oilwidthmax, 
    isnull(cz.efectivwidthmin,0) as efectivwidthmin, 
    isnull(cz.efectivwidthmax,0) as efectivwidthmax, 
    isnull(cz.koafporistmin,0) as koafporistmin, 
    isnull(cz.koafporistmax,0) as koafporistmax, 
    CASE 
     cz.__$operation 
     WHEN 1 THEN 'DELETE' 
     WHEN 2 THEN 'INSERT' 
     WHEN 3 THEN 'Before UPDATE' 
     WHEN 4 THEN 'After UPDATE' 
    END operation, 
    map.tran_begin_time as beginT, 
    map.tran_end_time as endT, 
    ROW_NUMBER() OVER (PARTITION BY cz.GUID ORDER BY map.tran_end_time ASC) as rn 
FROM 
    cdc.fn_cdc_get_all_changes_dbo_EXT_GeolObject_KategZalezh(sys.fn_cdc_get_min_lsn('dbo_EXT_GeolObject_KategZalezh'), sys.fn_cdc_get_max_lsn(), 'all') AS cz 
INNER JOIN 
    [cdc].[lsn_time_mapping] map ON cz.[__$start_lsn] = map.start_lsn 
), 

History2 AS 
(
    SELECT id, field, val, operation, beginT, endT, rn FROM History 
    unpivot ([val] for field in 
    (
    --category, 
    area, 
    oilwidthmin, 
    oilwidthmax, 
    efectivwidthmin, 
    efectivwidthmax, 
    koafporistmin, 
    koafporistmax))t  
    where id = '2D166098-7CBD-4622-9EB0-000070506FE6' 
) 

-- return the values that were inserted first 
SELECT 
    a.* 
FROM 
    History2 a 
WHERE 
    a.rn=1 

UNION ALL 

-- ... and then return only the values that are different from the previous ones 
SELECT 
    a.* 
FROM 
    History2 a 
INNER JOIN 
    History2 b ON a.id = b.id AND a.field=b.field AND a.rn = b.rn-1 AND a.value<>b.value 
WHERE 
    a.rn>1 

BTW;您还可以配置CDC以仅跟踪某些列中的更改,而不是整个表中的更改。查看sys.sp_cdc_enable_table存储过程的@captured_column_list。

+0

据我所知,我必须创建两个临时表并通过过滤器将它们联合起来:a.id = b.id AND a.field = b.field AND a.rn = b.rn-1 AND a.value <> b.value'。我对吗? – Seva

+0

您不需要创建任何临时表;你只需提到两次CTE(History2)。看看建议的查询。 – saso

+0

你的例子返回了几个错误:'靠近关键字的语法不正确'与'。'和'不正确的语法靠近',''我也不会在History2中隐藏查询。据我所知'unpivot'适用于结果表,但在历史2中没有任何表。 – Seva