为了在 Oracle 和 SQL Server 表之间进行快速、高级的比较,您可以使用函数 STANDARD_HASH 和 HASH_BYTES 的聚合。
Oracle 代码
--Create a simple table.
create table table1
(
id number,
contractdatetime date,
Attr3 varchar2(100),
Attr4 varchar2(100),
Attr5 varchar2(100)
);
--Insert 4 rows, the first three will be identical between databases,
--the last row will be different.
insert into table1 values (1, date '2000-01-01', 'a', 'a', 'a');
insert into table1 values (2, date '2000-01-01', 'b', 'b', 'b');
insert into table1 values (2, date '2000-01-02', null, null, null);
insert into table1 values (3, date '2000-01-02', 'Oracle', 'Oracle', 'Oracle');
commit;
select
id,
--Format the number
trim(to_number(
--Sum per group.
sum(
--Convert to a number.
to_number(
--Get the first 14 bytes. This seems to be the maximum that SQL Server can handle
--before it runs into math errors.
substr(
--Hash the value.
standard_hash(
--Concatenate the values using (hopefully) unique strings to separate the
--columns and represent NULLs (because the hashing functions treat nulls differently.)
nvl(to_char(contractdatetime, 'YYYY-MM-DD HH24:MI:SS'), 'null') ||
'-1-' || nvl(attr3, 'null') || '-2-' || nvl(attr3, 'null') || '-3-' || nvl(attr3, 'null')
, 'MD5')
, 1, 14)
, 'xxxxxxxxxxxxxxxxxxxx'))
, '99999999999999999999')) hash
from table1
group by id
order by 1;
SQL Server 代码
create table table1
(
id numeric,
contractdatetime datetime,
Attr3 varchar(100),
Attr4 varchar(100),
Attr5 varchar(100)
);
insert into table1 values (1, cast('2000-01-01 00:00:00.000' as datetime), 'a', 'a', 'a');
insert into table1 values (2, cast('2000-01-01 00:00:00.000' as datetime), 'b', 'b', 'b');
insert into table1 values (2, cast('2000-01-02 00:00:00.000' as datetime), null, null, null);
insert into table1 values (3, cast('2000-01-02 00:00:00.000' as datetime), 'SQL Server', 'SQL Server', 'SQL Server');
commit;
select
id,
sum(
convert(bigint, convert(varbinary,
substring(
hashbytes('MD5',
isnull(convert(varchar(19), contractdatetime, 20), 'null') +
'-1-' + isnull(attr3, 'null') + '-2-' + isnull(attr3, 'null') + '-3-' + isnull(attr3, 'null'))
, 1, 7)
, 1))) hash
from table1
group by id
order by 1;
结果
正如预期的那样,前两组的哈希值相同,而第三组的哈希值不同。
Oracle:
ID HASH
1 50696302970576522
2 69171702324546493
3 50787287321473273
SQL Server
ID HASH
1 50696302970576522
2 69171702324546493
3 7440319042693061
这是Oracle fiddle 和SQL Server fiddle。
问题
- 我认为此解决方案仅在数据库使用相似字符集或仅使用在不同字符集中通常编码相同的前 127 个 ASCII 字符时才有效。
- 哈希冲突的可能性很高(也许是不合理的)。 MD5 散列不足以防止加密攻击,但它们足以比较数据集。问题是我必须使用子字符串来使数学适用于 SQL Server。这可能是我对 SQL Server 不够了解的错——BIGIINTS 应该支持大约 19 位的精度,但我的数学只能达到 14 位。我可能在某个地方有一个转换错误。如果您遇到太多碰撞或溢出问题,您可能需要使用“14”和“7”数字。 (Oracle 为 14,根据显示的十六进制字符计数。SQL Server 为 7,根据每个十六进制字符可以表示的字符数计数,即 0.5。)