13

我想创建一个 sql 查询(或 plpgsql),它将 md5() 所有给定的行,无论类型如何。但是,在下面,如果一个为空,则哈希为空:

UPDATE thetable 
    SET hash = md5(accountid || accounttype || createdby || editedby);

我稍后使用散列来比较唯一性,因此空散列不适用于此用例。

问题在于它处理连接空值的方式。例如:

thedatabase=# SELECT accountid || accounttype || createdby  || editedby 
                 FROM thetable LIMIT 5;  

1Type113225  
<NULL>
2Type11751222 
3Type10651010 
4Type10651

如果我知道类型,我可以使用 coalesce 或 CASE 语句;但是,我有很多表,我不会提前知道每一列的类型。

4

4 回答 4

46

对此有更优雅的解决方案。

在 Postgres 中,SELECT允许使用表名 in 并且它的类型为ROW. 如果将其强制转换为 type TEXT,它会将所有列以字符串形式连接在一起,实际上是 JSON。

有了这个,您可以获得md5所有列,如下所示:

SELECT md5(mytable::TEXT)
FROM mytable

如果您只想使用某些列,请使用ROW构造函数并将其转换为TEXT

SELECT md5(ROW(col1, col2, col3)::TEXT)
FROM mytable

这个解决方案的另一个不错的特性是,它与空字符串md5不同。NULL

强制性SQLFiddle

于 2013-01-29T06:02:10.367 回答
5

您也可以使用其他类似于 mvp 的解决方案。而不是使用 Amazon Redshift 不支持的 ROW() 函数...

无效操作:目标列表中不支持隐式或显式 ROW 表达式;

我的建议是使用 NVL2 和 CAST 函数将不同类型的列转换为 CHAR,只要根据文档该类型与所有 Redshift 数据类型兼容。下面是一个如何在 Redshift 中实现null proof MD5 的示例。

SELECT md5(NVL2(col1,col1::char,''), 
           NVL2(col2,col2::char,''), 
           NVL2(col3,col3::char,''))
FROM mytable

这可能会在不将第二个 NVL2 函数参数转换为 char 的情况下工作,但如果您尝试从具有空值的日期列中获取 md5,它肯定会失败。我希望这对某人有帮助。

于 2016-01-06T16:45:03.250 回答
2

您是否尝试过使用CONCAT()?我刚刚在我的 PG 9.1 安装中尝试过:

SELECT CONCAT('aaaa',1111,'bbbb');     => aaaa1111bbbb
SELECT CONCAT('aaaa',null,'bbbb');     => aaaabbbb

因此,您可以尝试:

SELECT MD5(CONCAT(column1, column2, column3, column_n))    => md5_hash string here
于 2013-01-29T05:23:11.723 回答
0

选择 MD5(cast(p as text)) from accounting_cfop as p

于 2020-04-27T03:56:04.863 回答