Maybe you need to squeeze 64 hex characters (32 bytes) into something smaller while maintaining human-readability. This might be useful if you've de-identified a column using the SHA256 function, but you have a field width limitation of 40 characters, for example.
The SQL expression below condenses 64 hex characters (or less) into 40 human-readable characters, using Base85 encoding. Base85 encoding is nice because it fits binary data of N bytes into a string of N*1.25 human-readable characters.
This expression isn't terribly fast, but on our 8-node cluster it encodes 10 million distinct values in well under a minute. That time includes running SHA256() on the input values as well.
This SQL expression was adapted from the definition of Base85 encoding found on Wikipedia: Ascii85
Normally one would request dbadmins to create a user-defined function (UDF) for this, but we're discouraged from that due to the maintenance overhead of maintaining many clusters.
WITH HexData AS (
SELECT TO_HEX('Man '::VARBINARY) AS "x"
UNION ALL SELECT TO_HEX('Man is distinguished, not only b'::VARBINARY) AS "x"
UNION ALL SELECT SHA256('Man is distinguished, not only by his reason, but by this singular passion from other animals, which is a lust of the mind, that by a perseverance of delight in the continued and indefatigable generation of knowledge, exceeds the short vehemence of any carnal pleasure.')
)
SELECT
-- Input value "x" should be 64 hex characters (or less).
-- Output value "Base85Encoded" is 40 human-readable characters in the 90-character range ASCII(33) to ASCII(122).
-- Note that numbers 52200625, 614125, and 7225 are equal to the number 85 raised to the power of 4, 3, and 2, respectively.
"x",
-- ##### 4-tuple 1 ##### Base85 characters 1 - 5
CHR(33 + TRUNC(HEX_TO_INTEGER(SUBSTRING(LPAD("x", 64, '0'), 1, 8)) / 52200625, 0)::INT) ||
CHR(33 + TRUNC(MOD(HEX_TO_INTEGER(SUBSTRING(LPAD("x", 64, '0'), 1, 8)), 52200625) / 614125, 0)::INT) ||
CHR(33 + TRUNC(MOD(MOD(HEX_TO_INTEGER(SUBSTRING(LPAD("x", 64, '0'), 1, 8)), 52200625), 614125) / 7225, 0)::INT) ||
CHR(33 + TRUNC(MOD(MOD(MOD(HEX_TO_INTEGER(SUBSTRING(LPAD("x", 64, '0'), 1, 8)), 52200625), 614125), 7225) / 85, 0)::INT) ||
CHR(33 + MOD(MOD(MOD(MOD(HEX_TO_INTEGER(SUBSTRING(LPAD("x", 64, '0'), 1, 8)), 52200625), 614125), 7225), 85)::INT) ||
-- ##### 4-tuple 2 ##### Base85 characters 6 - 10
CHR(33 + TRUNC(HEX_TO_INTEGER(SUBSTRING(LPAD("x", 64, '0'), 9, 8)) / 52200625, 0)::INT) ||
CHR(33 + TRUNC(MOD(HEX_TO_INTEGER(SUBSTRING(LPAD("x", 64, '0'), 9, 8)), 52200625) / 614125, 0)::INT) ||
CHR(33 + TRUNC(MOD(MOD(HEX_TO_INTEGER(SUBSTRING(LPAD("x", 64, '0'), 9, 8)), 52200625), 614125) / 7225, 0)::INT) ||
CHR(33 + TRUNC(MOD(MOD(MOD(HEX_TO_INTEGER(SUBSTRING(LPAD("x", 64, '0'), 9, 8)), 52200625), 614125), 7225) / 85, 0)::INT) ||
CHR(33 + MOD(MOD(MOD(MOD(HEX_TO_INTEGER(SUBSTRING(LPAD("x", 64, '0'), 9, 8)), 52200625), 614125), 7225), 85)::INT) ||
-- ##### 4-tuple 3 ##### Base85 characters 11 - 15
CHR(33 + TRUNC(HEX_TO_INTEGER(SUBSTRING(LPAD("x", 64, '0'), 17, 8)) / 52200625, 0)::INT) ||
CHR(33 + TRUNC(MOD(HEX_TO_INTEGER(SUBSTRING(LPAD("x", 64, '0'), 17, 8)), 52200625) / 614125, 0)::INT) ||
CHR(33 + TRUNC(MOD(MOD(HEX_TO_INTEGER(SUBSTRING(LPAD("x", 64, '0'), 17, 8)), 52200625), 614125) / 7225, 0)::INT) ||
CHR(33 + TRUNC(MOD(MOD(MOD(HEX_TO_INTEGER(SUBSTRING(LPAD("x", 64, '0'), 17, 8)), 52200625), 614125), 7225) / 85, 0)::INT) ||
CHR(33 + MOD(MOD(MOD(MOD(HEX_TO_INTEGER(SUBSTRING(LPAD("x", 64, '0'), 17, 8)), 52200625), 614125), 7225), 85)::INT) ||
-- ##### 4-tuple 4 ##### Base85 characters 16 - 20
CHR(33 + TRUNC(HEX_TO_INTEGER(SUBSTRING(LPAD("x", 64, '0'), 25, 8)) / 52200625, 0)::INT) ||
CHR(33 + TRUNC(MOD(HEX_TO_INTEGER(SUBSTRING(LPAD("x", 64, '0'), 25, 8)), 52200625) / 614125, 0)::INT) ||
CHR(33 + TRUNC(MOD(MOD(HEX_TO_INTEGER(SUBSTRING(LPAD("x", 64, '0'), 25, 8)), 52200625), 614125) / 7225, 0)::INT) ||
CHR(33 + TRUNC(MOD(MOD(MOD(HEX_TO_INTEGER(SUBSTRING(LPAD("x", 64, '0'), 25, 8)), 52200625), 614125), 7225) / 85, 0)::INT) ||
CHR(33 + MOD(MOD(MOD(MOD(HEX_TO_INTEGER(SUBSTRING(LPAD("x", 64, '0'), 25, 8)), 52200625), 614125), 7225), 85)::INT) ||
-- ##### 4-tuple 5 ##### Base85 characters 21 - 25
CHR(33 + TRUNC(HEX_TO_INTEGER(SUBSTRING(LPAD("x", 64, '0'), 33, 8)) / 52200625, 0)::INT) ||
CHR(33 + TRUNC(MOD(HEX_TO_INTEGER(SUBSTRING(LPAD("x", 64, '0'), 33, 8)), 52200625) / 614125, 0)::INT) ||
CHR(33 + TRUNC(MOD(MOD(HEX_TO_INTEGER(SUBSTRING(LPAD("x", 64, '0'), 33, 8)), 52200625), 614125) / 7225, 0)::INT) ||
CHR(33 + TRUNC(MOD(MOD(MOD(HEX_TO_INTEGER(SUBSTRING(LPAD("x", 64, '0'), 33, 8)), 52200625), 614125), 7225) / 85, 0)::INT) ||
CHR(33 + MOD(MOD(MOD(MOD(HEX_TO_INTEGER(SUBSTRING(LPAD("x", 64, '0'), 33, 8)), 52200625), 614125), 7225), 85)::INT) ||
-- ##### 4-tuple 6 ##### Base85 characters 26 - 30
CHR(33 + TRUNC(HEX_TO_INTEGER(SUBSTRING(LPAD("x", 64, '0'), 41, 8)) / 52200625, 0)::INT) ||
CHR(33 + TRUNC(MOD(HEX_TO_INTEGER(SUBSTRING(LPAD("x", 64, '0'), 41, 8)), 52200625) / 614125, 0)::INT) ||
CHR(33 + TRUNC(MOD(MOD(HEX_TO_INTEGER(SUBSTRING(LPAD("x", 64, '0'), 41, 8)), 52200625), 614125) / 7225, 0)::INT) ||
CHR(33 + TRUNC(MOD(MOD(MOD(HEX_TO_INTEGER(SUBSTRING(LPAD("x", 64, '0'), 41, 8)), 52200625), 614125), 7225) / 85, 0)::INT) ||
CHR(33 + MOD(MOD(MOD(MOD(HEX_TO_INTEGER(SUBSTRING(LPAD("x", 64, '0'), 41, 8)), 52200625), 614125), 7225), 85)::INT) ||
-- ##### 4-tuple 7 ##### Base85 characters 31 - 35
CHR(33 + TRUNC(HEX_TO_INTEGER(SUBSTRING(LPAD("x", 64, '0'), 49, 8)) / 52200625, 0)::INT) ||
CHR(33 + TRUNC(MOD(HEX_TO_INTEGER(SUBSTRING(LPAD("x", 64, '0'), 49, 8)), 52200625) / 614125, 0)::INT) ||
CHR(33 + TRUNC(MOD(MOD(HEX_TO_INTEGER(SUBSTRING(LPAD("x", 64, '0'), 49, 8)), 52200625), 614125) / 7225, 0)::INT) ||
CHR(33 + TRUNC(MOD(MOD(MOD(HEX_TO_INTEGER(SUBSTRING(LPAD("x", 64, '0'), 49, 8)), 52200625), 614125), 7225) / 85, 0)::INT) ||
CHR(33 + MOD(MOD(MOD(MOD(HEX_TO_INTEGER(SUBSTRING(LPAD("x", 64, '0'), 49, 8)), 52200625), 614125), 7225), 85)::INT) ||
-- ##### 4-tuple 8 ##### Base85 characters 36 - 40
CHR(33 + TRUNC(HEX_TO_INTEGER(SUBSTRING(LPAD("x", 64, '0'), 57, 8)) / 52200625, 0)::INT) ||
CHR(33 + TRUNC(MOD(HEX_TO_INTEGER(SUBSTRING(LPAD("x", 64, '0'), 57, 8)), 52200625) / 614125, 0)::INT) ||
CHR(33 + TRUNC(MOD(MOD(HEX_TO_INTEGER(SUBSTRING(LPAD("x", 64, '0'), 57, 8)), 52200625), 614125) / 7225, 0)::INT) ||
CHR(33 + TRUNC(MOD(MOD(MOD(HEX_TO_INTEGER(SUBSTRING(LPAD("x", 64, '0'), 57, 8)), 52200625), 614125), 7225) / 85, 0)::INT) ||
CHR(33 + MOD(MOD(MOD(MOD(HEX_TO_INTEGER(SUBSTRING(LPAD("x", 64, '0'), 57, 8)), 52200625), 614125), 7225), 85)::INT) AS "Base85Encoded"
FROM HexData
;
Results:
| x | Base85Encoded |
|---|---|
| 4d616e20 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!9jqo^ |
| 4d616e2069732064697374696e677569736865642c206e6f74206f6e6c792062 | 9jqo^BlbD-BleB1DJ+*+F(f,q/0JhKFCj@.4 |
| 78fe75026c4390ceccc4e9e6a9428ba8ae5968b458e60b5eebecd682cf24bbf2 | GlDgeCdX<0bf&c.WBuNAY$#GF=QTutlg32ScQp-n |
