0. 示例表數據
root@localhost[demo]> select * from demo.tcustmer;
+-----------+--------------------+-------------+-------+
| CUST_CODE | NAME | CITY | STATE |
+-----------+--------------------+-------------+-------+
| ANN | ANN'S BOATS | NEW YORK | NY |
| BILL | BILL'S USED CARS | DENVER | CO |
| DAVE | DAVE'S PLANES INC. | TALLAHASSEE | FL |
| JANE | ROCKY FLYER INC. | DENVER | CO |
| WILL | BG SOFTWARE CO. | SEATTLE | WA |
+-----------+--------------------+-------------+-------+
1. MySQL端數據校驗
1.1 MySQL列轉行
-- 設置字段拼接最大長度,防止字段過多顯示不全
SET @@GLOBAL.GROUP_CONCAT_MAX_LEN=10000,@@GROUP_CONCAT_MAX_LEN=10000;
SELECT @@GLOBAL.GROUP_CONCAT_MAX_LEN,@@GROUP_CONCAT_MAX_LEN;
-- 查詢COLUMNS表元數據做字段拼接
SELECT TABLE_NAME,
CONCAT(GROUP_CONCAT(COLUMN_NAME ORDER BY ORDINAL_POSITION SEPARATOR ',')) AS ALL_COLUMNS
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = 'demo'
AND TABLE_NAME = 'tcustmer'
GROUP BY TABLE_NAME;
-- 輸出結果如下
+------------+---------------------------+
| TABLE_NAME | ALL_COLUMNS |
+------------+---------------------------+
| tcustmer | CUST_CODE,NAME,CITY,STATE |
+------------+---------------------------+
1.2 MySQL數據校驗
-- 使用MD5對拼接的字段做校驗,生成16進制校驗碼
SELECT upper(MD5(CONCAT_WS('',CUST_CODE,NAME,CITY,STATE))) as MD5 FROM tcustmer;
+----------------------------------+
| MD5 |
+----------------------------------+
| 9B1A3721FB80C9E75C136C5CFBB7FFC1 |
| E0ACAC3ADA8E3AC75CE08CC32DDB4139 |
| 4ECA8A64D252C69709344EE78BCB5923 |
| D264438E50624428039DC6254851DB52 |
| 1828B98ADF2E5866FA895DCB5B3A3833 |
+----------------------------------+
-- 由於後續需要使用到bit_xor做數值異或,將校驗碼截取前6位做比對
SELECT left(upper(MD5(CONCAT_WS('',CUST_CODE,NAME,CITY,STATE))),6) as MD5 FROM tcustmer;
+--------+
| MD5 |
+--------+
| 9B1A37 |
| E0ACAC |
| 4ECA8A |
| D26443 |
| 1828B9 |
+--------+
-- 將16進制的MD5前6位字符串轉換爲10進制
SELECT conv(left(upper(MD5(CONCAT_WS('',CUST_CODE,NAME,CITY,STATE))),6),16,10) as MD5 FROM tcustmer;
+----------+
| MD5 |
+----------+
| 10164791 |
| 14724268 |
| 5163658 |
| 13788227 |
| 1583289 |
+----------+
-- 最後對10進制的MD5值做異或算法生成唯一校驗值
SELECT bit_xor(conv(left(upper(MD5(CONCAT_WS('',CUST_CODE,NAME,CITY,STATE))),6),16,10)) as MD5 FROM tcustmer;
+----------+
| MD5 |
+----------+
| 16724203 |
+----------+
2. Oracle端數據校驗
由於Oracle端默認沒有bit_xor函數,需要自行創建,且Oracle端MD5校驗值是由
DBMS_OBFUSCATION_TOOLKIT.MD5
包生成,爲了方便也重新創建函數進行封裝
2.1 Oracle列轉行
-- 查詢DBA_TAB_COLUMNS生成拼接字段
col table_name for a32
col column_concat for a40
-- 使用listagg聚合函數
select table_name, listagg(COLUMN_NAME, '||') within group(order by column_id) column_concat
from DBA_TAB_COLUMNS
where OWNER = upper('scott')
and table_name=upper('tcustmer')
group by table_name;
-- 輸出結果示例
TABLE_NAME COLUMN_CONCAT
--------- ----------------------------------------
TCUSTMER CUST_CODE||NAME||CITY||STATE
2.2 創建Oracle端MD5函數
-- 該函數只是爲了使MD5的用法與MySQL一致
CREATE OR REPLACE FUNCTION MD5(PASSWD IN VARCHAR2) RETURN VARCHAR2 IS
RETVAL VARCHAR2(32);
BEGIN
RETVAL := UTL_RAW.CAST_TO_RAW(DBMS_OBFUSCATION_TOOLKIT.MD5(INPUT_STRING => PASSWD));
RETURN RETVAL;
END;
/
-- 調用測試
col MD5 for a32
select md5(CUST_CODE||NAME||CITY||STATE) as MD5 from TCUSTMER;
-- 生成的結果與MySQL完全一致,符合預期
MD5
--------------------------------
1828B98ADF2E5866FA895DCB5B3A3833
D264438E50624428039DC6254851DB52
4ECA8A64D252C69709344EE78BCB5923
E0ACAC3ADA8E3AC75CE08CC32DDB4139
9B1A3721FB80C9E75C136C5CFBB7FFC1
2.3 創建Oracle端bit_xor函數
create or replace type xor_type as object (
cat_val number,
static function ODCIAggregateInitialize(cs_ctx In Out xor_type) return number,
member function ODCIAggregateIterate(self In Out xor_type,value in number) return number,
member function ODCIAggregateMerge(self In Out xor_type,ctx2 In Out xor_type) return number,
member function ODCIAggregateTerminate(self In Out xor_type,returnValue Out number,flags in number) return number
)
/
create or replace type body xor_type is
static function ODCIAggregateInitialize(cs_ctx IN OUT xor_type) return number
is
begin
cs_ctx := xor_type(0);
return ODCIConst.Success;
end;
member function ODCIAggregateIterate(self IN OUT xor_type,
value IN number )
return number
is
begin
self.cat_val := value + self.cat_val - BITAND(value, self.cat_val) * 2;
return ODCIConst.Success;
end;
member function ODCIAggregateTerminate(self IN Out xor_type,
returnValue OUT number,
flags IN number)
return number
is
begin
returnValue := self.cat_val;
return ODCIConst.Success;
end;
member function ODCIAggregateMerge(self IN OUT xor_type,
ctx2 IN Out xor_type)
return number
is
begin
self.cat_val := self.cat_val + ctx2.cat_val - BITAND(self.cat_val, ctx2.cat_val) * 2;
return ODCIConst.Success;
end;
end;
/
CREATE OR REPLACE
FUNCTION bit_xor(input number)
RETURN number
PARALLEL_ENABLE AGGREGATE USING xor_type;
/
-- 調用驗證
SCOTT@zhenxing> select bit_xor(PRODUCT_PRICE) from TCUSTORD;
BIT_XOR(PRODUCT_PRICE)
----------------------
167872
-- 在MySQL端執行默認的bit_xor函數,對比結果一致
root@localhost[demo]> select bit_xor(PRODUCT_PRICE) from TCUSTORD;
+------------------------+
| bit_xor(PRODUCT_PRICE) |
+------------------------+
| 167872 |
+------------------------+
2.4 Oracle數據校驗
-- 生成MD5值
SCOTT@zhenxing> col MD5 for a32
SCOTT@zhenxing> select md5(CUST_CODE||NAME||CITY||STATE) as MD5 from TCUSTMER order by CUST_CODE;
MD5
--------------------------------
9B1A3721FB80C9E75C136C5CFBB7FFC1
E0ACAC3ADA8E3AC75CE08CC32DDB4139
4ECA8A64D252C69709344EE78BCB5923
D264438E50624428039DC6254851DB52
1828B98ADF2E5866FA895DCB5B3A3833
-- 後續需要使用到bit_xor做數值異或,將校驗碼截取前6位做比對
SCOTT@zhenxing> select substr(md5(CUST_CODE||NAME||CITY||STATE),0,6) as MD5 from TCUSTMER order by CUST_CODE;
MD5
--------------------------------
9B1A37
E0ACAC
4ECA8A
D26443
1828B9
-- 將16進制的MD5前6位字符串轉換爲10進制
SCOTT@zhenxing> col MD5 for 999999999999999999
SCOTT@zhenxing> select to_number(substr(md5(CUST_CODE||NAME||CITY||STATE),0,6),'xxxxxxxxxx') as MD5 from TCUSTMER order by CUST_CODE;
MD5
-------------------
10164791
14724268
5163658
13788227
1583289
-- 最後對10進制的MD5值做異或算法生成唯一校驗值
-- 對比MySQL端校驗值,完全一致
SCOTT@zhenxing> select bit_xor(to_number(substr(md5(CUST_CODE||NAME||CITY||STATE),0,6),'xxxxxxxxxx')) as MD5 from TCUSTMER order by CUST_CODE;
MD5
-------------------
16724203