mssql cdc update_mask 筛选仅在 TS 列中进行的更改
mssql cdc update_mask filter changes made only in column TS
我想在我的 mssql cdc table 中找到只有“TS”列已更改的行。
所以我找到了一些逻辑来检查特定列是否被更改(这有效),但我需要检查是否只有列 TS 被更改:
SET @colorder = sys.fn_cdc_get_column_ordinal('dbo_mytable', 'TS')
SELECT case when substring([__$update_mask],len([__$update_mask]) - ((@colorder-1)/8),1) & power(2,(@colorder-1)%8) > 0 then 1 else 0 end
FROM cdc.fn_cdc_get_all_changes_dbo_MYTABLE(@from_lsn, @to_lsn, 'all') PD
我想写这样的函数已经有一段时间了,谢谢你给了我一个真正去做的理由。
请自己做一些单元测试,我只做了一些非常基本的检查
-- inline tabular function because it's more versatile
-- cross applies used purely for ease of reading,
-- could just make nested calls but hard to read. Up to you.
-- pass null to flip, otherwise pass explicit value you want the bit to be set to
create function dbo.setbit(@b varbinary(128), @bitpos tinyint, @value bit = null)
returns table as
return
(
select result = cast(result.val as varbinary(128))
from (select len(@b) - ((@bitpos - 1) / 8)) bytepos(val)
cross apply (select substring(@b, bytepos.val, 1)) byte(val)
cross apply (select power(2, (@bitpos - 1) % 8)) mask(val)
cross apply (
select cast
(
case @value
when 1 then byte.val | mask.val
when 0 then byte.val & ~mask.val
else byte.val ^ mask.val
end
as binary(1)
)
) newbyte(val)
cross apply (select stuff(@b, bytepos.val, 1, newbyte.val)) result(val)
);
-- scalar wrapper for tabular function
create function dbo.setbitscalar(@b varbinary(128), @bitpos tinyint, @value bit = null)
returns varbinary(128) as
begin
return (select result from dbo.setbit(@b, @bitpos, @value));
end
-- how it works
declare @b varbinary(128) = 0x0101 -- 2 bytes!
select
dbo.setbitscalar(@b, 1, 1), -- set bit 1 to 1
dbo.setbitscalar(@b, 1, 0), -- set bit 1 to 0
dbo.setbitscalar(@b, 1, default) -- flip bit 1
-- how to use it in your case:
-- set the @colorder bit in the mask to zero,
-- then see if the resulting mask is zero
-- if it is, then only TS changed
SET @colorder = sys.fn_cdc_get_column_ordinal('dbo_mytable', 'TS')
select only_TS_changed = iif(t.result = 0x, 1, 0)
from cdc.fn_cdc_get_all_changes_dbo_MYTABLE(@from_lsn, @to_lsn, 'all') PD
cross apply dbo.setbit(PD.[__$update_mask], @colorder, 0) t
我想在我的 mssql cdc table 中找到只有“TS”列已更改的行。
所以我找到了一些逻辑来检查特定列是否被更改(这有效),但我需要检查是否只有列 TS 被更改:
SET @colorder = sys.fn_cdc_get_column_ordinal('dbo_mytable', 'TS')
SELECT case when substring([__$update_mask],len([__$update_mask]) - ((@colorder-1)/8),1) & power(2,(@colorder-1)%8) > 0 then 1 else 0 end
FROM cdc.fn_cdc_get_all_changes_dbo_MYTABLE(@from_lsn, @to_lsn, 'all') PD
我想写这样的函数已经有一段时间了,谢谢你给了我一个真正去做的理由。
请自己做一些单元测试,我只做了一些非常基本的检查
-- inline tabular function because it's more versatile
-- cross applies used purely for ease of reading,
-- could just make nested calls but hard to read. Up to you.
-- pass null to flip, otherwise pass explicit value you want the bit to be set to
create function dbo.setbit(@b varbinary(128), @bitpos tinyint, @value bit = null)
returns table as
return
(
select result = cast(result.val as varbinary(128))
from (select len(@b) - ((@bitpos - 1) / 8)) bytepos(val)
cross apply (select substring(@b, bytepos.val, 1)) byte(val)
cross apply (select power(2, (@bitpos - 1) % 8)) mask(val)
cross apply (
select cast
(
case @value
when 1 then byte.val | mask.val
when 0 then byte.val & ~mask.val
else byte.val ^ mask.val
end
as binary(1)
)
) newbyte(val)
cross apply (select stuff(@b, bytepos.val, 1, newbyte.val)) result(val)
);
-- scalar wrapper for tabular function
create function dbo.setbitscalar(@b varbinary(128), @bitpos tinyint, @value bit = null)
returns varbinary(128) as
begin
return (select result from dbo.setbit(@b, @bitpos, @value));
end
-- how it works
declare @b varbinary(128) = 0x0101 -- 2 bytes!
select
dbo.setbitscalar(@b, 1, 1), -- set bit 1 to 1
dbo.setbitscalar(@b, 1, 0), -- set bit 1 to 0
dbo.setbitscalar(@b, 1, default) -- flip bit 1
-- how to use it in your case:
-- set the @colorder bit in the mask to zero,
-- then see if the resulting mask is zero
-- if it is, then only TS changed
SET @colorder = sys.fn_cdc_get_column_ordinal('dbo_mytable', 'TS')
select only_TS_changed = iif(t.result = 0x, 1, 0)
from cdc.fn_cdc_get_all_changes_dbo_MYTABLE(@from_lsn, @to_lsn, 'all') PD
cross apply dbo.setbit(PD.[__$update_mask], @colorder, 0) t