我有一个十六进制格式的数据字符串。类似的东西
'0x00000000000000000000000000000000000000000000000000000000000000006cc09155dd769741d7cd1c6a3334a1aeef62da2d0e92a39230becd6e56c2ad490000000000000000000000000000000000000000000000007ce66c50e2840000' as data
我知道
substring(data, 131)
是一个很大的数字。
对于较小的数字我可以很好地通过
SAFE_CAST(CONCAT('0x', SUBSTRING(data, 131)) AS INT64)
。
SAFE_CAST(CONCAT('0x', SUBSTRING(data, 131)) AS NUMERIC)
(或大数字)不起作用。
我尝试了类似
FROM_HEX(SUBSTRING(data, 131))
的方法来获取字节格式。但也找不到任何让 BYTE
到 NUMERIC
的好选择。
对于这么大的数字,甚至
BIGNUMERIC
都无法容纳它们,所以你必须作为字符串来工作。常规 BigQUery 函数将无法处理这些数字,因此我建议您使用 UDF
:
CREATE TEMP FUNCTION from_hex_to_intstring(hex STRING)
RETURNS STRING
LANGUAGE js AS r"""
yourNumber = BigInt(hex,16);
return yourNumber;
""";
select from_hex_to_intstring('0x00000000000000000000000000000000000000000000000000000000000000006cc09155dd769741d7cd1c6a3334a1aeef62da2d0e92a39230becd6e56c2ad490000000000000000000000000000000000000000000000007ce66c50e2840000') data;
select from_hex_to_intstring('0x00000000000000000000000000000000000000000009ed194db19b238c000000') data
结果:
-------------------------------
Row | data
1 | 5695815805094697319662327076913960577653781492348607706655047793592681546373383993595483025021696631917691807178407718241565809060633202962632700189736960
-------------------------------
Row | data
1 | 12000000000000000000000000
-------------------------------
奖励1: 如果十六进制不是那么大,您可以将其返回为
NUMERIC
或 BIGNUMERIC
:
select cast(from_hex_to_intstring(<hex string>) as NUMERIC)
奖励2: 如果您想修剪十六进制上的零,请使用以下(但上面的功能不需要):
select concat("0x",ltrim('0x00000000000000000000000000000000000000000009ed194db19b238c000000',"0x")) as data
-------------------------------
Row | data
1 | 0x9ed194db19b238c000000
-------------------------------
对于那些来这里寻找答案但无法使用 UDF 因为他们想在物化视图中包含此逻辑的人来说,以下可能是一个解决方案。对于那些也使用 EVM 数据并且还需要应用
decimals
值的人,我们可以通过在计算过程中应用小数位来将更大的值放入 BIGNUMERIC 数据类型中。
我知道它的可读性不太好,但我们正在 BigQuery 的限制范围内工作。
SQL:
WITH input AS (
SELECT
'0x0000000000000000000f00a0000a000aaa00c9f78d2893e40000c9f78d2893e4' AS `value`
, 18 AS decimals
UNION ALL
SELECT
'0x00000000000000000000000000000000000000000009ed194db19b238c000000' AS `value`
, 0 AS decimals
)
SELECT
(SELECT SUM(CAST((c << MOD(ARRAY_LENGTH(TO_CODE_POINTS(FROM_HEX(LTRIM(`value`, '0x')))) - 1 - bit, 4) * 8) AS BIGNUMERIC) * (CAST(POWER(2,LEAST(128, FLOOR((ARRAY_LENGTH(TO_CODE_POINTS(FROM_HEX(LTRIM(`value`, '0x'))))- 1 - bit) / 4)*4*8)) AS BIGNUMERIC) / CAST(POWER(10,decimals) AS BIGNUMERIC)) * CAST(POWER(2,GREATEST(0, (FLOOR((ARRAY_LENGTH(TO_CODE_POINTS(FROM_HEX(LTRIM(`value`, '0x'))))- 1 - bit) / 4)*4*8)-128)) AS BIGNUMERIC)) FROM UNNEST(TO_CODE_POINTS(FROM_HEX(LTRIM(`value`, '0x')))) AS c WITH OFFSET bit) AS `value`
FROM
input
结果:
---------------------------------------------------------------
Row | value
---------------------------------------------------------------
1 | 1436948410046754829959694029135256495.417162625387631588
---------------------------------------------------------------
2 | 12000000000000000000000000
---------------------------------------------------------------