2017-08-10 34 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