mySQL:获取每一行的哈希值?

时间:2011-11-30 18:13:04

标签: mysql hash

目前我正在手动创建一个字符串,用于连接表格中每行的所有值。我正在为每一行散列此字符串以获取该行的当前值(/ status)的哈希值,我稍后将使用该哈希值来确定该行是否已更改。

而不是手动执行此操作,我的mySQL是否有内置的方式来获取每行的唯一哈希值?

5 个答案:

答案 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版上成功使用了。