目前我正在手动创建一个字符串,用于连接表格中每行的所有值。我正在为每一行散列此字符串以获取该行的当前值(/ status)的哈希值,我稍后将使用该哈希值来确定该行是否已更改。
而不是手动执行此操作,我的mySQL是否有内置的方式来获取每行的唯一哈希值?
答案 0 :(得分:21)
SELECT MD5(concat(field1, field2, field3, ...)) AS rowhash
但是你无法摆脱列出你想要的字段,因为concat(*)
不是一个选项(语法错误)。
答案 1 :(得分:2)
好吧,我制作了一个小脚本,可以完全按照自己的意愿行事,也许是别人想要的......所以这里......对于PHP来说...... 首先你必须列出表的列,然后你根据它们的类型为每个列创建一个“case when”语句并将其放在concat_ws语句中,然后用sha1哈希...我用过在非常大的表(600000+条记录)上使用此方法,并且在选择所有记录时速度非常好。另外我认为在concat_ws中连接所需的数据并在php或者你正在使用的任何东西中爆炸它会更快,但这只是一种预感......
<?
$query= mysql_query("SHOW COLUMNS FROM $table", $linklive);
while ($col = mysql_fetch_assoc($query)) {
$columns[] = mysql_real_escape_string($col['Field']);
if ($col['Key'] == 'PRI') {
$key = mysql_real_escape_string($col['Field']);
}
$columnsinfo[$col['Field']] = $col;
}
$dates = array("date","datetime","time");
$int = array("int","decimal");
$implcols = array();
foreach($columns as $col){
if(in_array($columnsinfo[$col]['Type'], $dates)){
$implcols[] = "(CASE WHEN (UNIX_TIMESTAMP(`$col`)=0 || `$col` IS NULL) THEN '[$col EMPTY]' ELSE `$col` END)";
}else{
list($type, $rest) = explode("(",$columnsinfo[$col]['Type']);
if(in_array($columnsinfo[$col]['Type'], $dates)){
$implcols[] = "(CASE WHEN ( `$col`=0 || `$col` IS NULL ) THEN '[$col EMPTY]' ELSE `$col` END)";
}else{
$implcols[] = "(CASE WHEN ( `$col`='' || `$col` IS NULL ) THEN '[$col EMPTY]' ELSE `$col` END)";
}
}
}
$keyslive = array();
//echo "SELECT $key SHA1(CONCAT_WS('',".implode(",", $columns).")) as compare FROM $table"; exit;
$q = "SELECT $key as `key`, SHA1(CONCAT_WS('',".implode(", ",$implcols).")) as compare FROM $table";
?>
答案 2 :(得分:1)
最好使用concat_ws()。例如两个相邻的列:12,3 =&gt; 1,23。
对不起,这还有一些问题。想想空值,空字符串,字符串可以包含','等...
需要一个程序来生成哈希语句,该语句应该将null替换为特定值(对于可以为空的列),并且还使用很少使用的char / byte作为分隔符。
答案 3 :(得分:1)
CONCAT
存在问题,例如CONCAT('ab', 'c')
与CONCAT('a', 'bc')
。两行不同,但结果相同。您可以使用CONCAT_WS(';', 'ab', 'c')
来获取ab;c
,但是如果CONCAT_WS(';', ';', '')
与CONCAT_WS(';', '', ';')
的情况仍然相同。
也CONCAT(NULL, 'c')
返回NULL
。
我认为最好的方法是使用QUOTE
:
SELECT MD5(CONCAT(QUOTE(c1), QUOTE(c2), QUOTE(c3))) AS row_hash FROM t1;
结果:select (concat(quote('a'), quote('bc'), quote('NULL'), quote(NULL), quote('\''), quote('')));
是:'a''bc''NULL'NULL'\''''
此外,请勿使用GROUP_CONCAT()获取表的哈希,它具有限制:https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_group_concat_max_len
相反,CHECKSUM TABLE
可能更好,但是您不能使用CHECKSUM TABLE
https://dev.mysql.com/doc/refman/5.7/en/checksum-table.html
答案 4 :(得分:0)
该聚会的聚会了,但是...
您可以添加一个updated
字段,每当行更改时该字段都会更新。
然后,您只需要跟踪时间戳,就可以像这样显示
updated: 2017-12-30 17:51:19
这样,您不仅知道如果行已更改,而且还知道何时是最后一次更新。
MySQL命令:
ALTER TABLE mytable ADD `updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
ON UPDATE CURRENT_TIMESTAMP;
默认精度是一秒(如果只不时检查行是否更改,就足够了)。但是如果需要,您可以设置几分之一秒的精度,例如微秒
ALTER TABLE mytable ADD `updated` timestamp(6) NOT NULL
DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6);
然后时间戳将显示为
updated: 2017-12-30 17:51:19.123456
Link to the documentation,这是8.0版,但我已经在5.7版上成功使用了。