检索没有主键但具有唯一字段的 CDC 净更改

Retrieve CDC net changes without primary key but with unique field

我想知道是否有可能检索类似于 cdc.fn_cdc_get_net_changes_<capture_instance>(from_lsn , to_lsn, 'all with mask') 的净更改,这些表没有主键但有一个约束确保一个(或多个)列) 是独一无二的。

我花了一些时间,但我认为我有一个可行的解决方案,如果有更好的解决方案或者您发现我的错误,请告诉我。

我们假设 table 的一个名为 capture_instance 的捕获实例具有唯一列 ID 和非唯一列 field1field2field3 和变量 @from_lsn@to_lsn.

WITH
cdc_all AS (
  -- Retrieve the change table with all changes
  SELECT *
  FROM cdc.fn_cdc_get_all_changes_capture_instance(@from_lsn, @to_lsn, 'all')
),
f AS (
  SELECT cdc_all.*, ops.[delete], ops.[insert], ops.[update], ops.[net_op]
  FROM cdc_all
  INNER JOIN (
    -- Retrieve three flags for insert, update and delete and the net operation
    -- also filter insert + delete pairs because it results in no change
    SELECT *
    FROM (
      SELECT ID
           , MAX(CASE WHEN __$operation = 1 THEN 1 ELSE 0 END) as [delete]
           , MAX(CASE WHEN __$operation = 2 THEN 1 ELSE 0 END) as [insert]
           , MAX(CASE WHEN __$operation = 4 THEN 1 ELSE 0 END) as [update]
           , MIN(__$operation) [net_op]
      FROM cdc_all
      GROUP BY ID
    ) ops
    WHERE NOT (ops.[delete] = 1 AND ops.[insert] = 1)
  ) ops ON cdc_all.ID = ops.ID
)
SELECT net.[max_lsn], f.[net_op] __$operation
     , (CASE WHEN net.__$update_mask != 0x0 THEN net.__$update_mask ELSE NULL END) __$update_mask
     , f.[ID], [field1], [field2], [field3]
FROM f
INNER JOIN (
  -- bitwise OR the __$update_mask of the updates
  -- also retrieve the last lsn of each row which should be used as the __$start_lsn of the result set
  SELECT ID
       , CAST(SUM(DISTINCT CAST((CASE WHEN f.[__$operation] = 4 AND f.[insert] != 1 THEN f.[__$update_mask] ELSE 0 END) as int)) as varbinary(2)) [__$update_mask]
       , MAX(__$start_lsn) [max_lsn]
  FROM f
  GROUP BY ID
) net ON f.ID = net.ID AND f.__$start_lsn = net.[max_lsn]

为了准确匹配 cdc.fn_cdc_get_net_changes_ 的行为,末尾的 varbinary 的大小应尽可能小以适合所有字段,但较大的值不会破坏功能。