如何在 AMAZON REDSHIFT 中将 userip 转换为整数

Posted

技术标签:

【中文标题】如何在 AMAZON REDSHIFT 中将 userip 转换为整数【英文标题】:How to Convert userip to integer in AMAZON REDSHIFT 【发布时间】:2013-06-28 20:19:54 【问题描述】:

刚开始玩并测试亚马逊的红移。我需要做的一件事是我可以在 sql 中轻松完成的操作是将 userip 更改为整数。这是在 mssql 中通过一个标量函数完成的,该函数使用 parsename 来分解 ip 编号并通过常量将它们倍增。

 CAST(

       (CAST(PARSENAME(@IP,4) AS BIGINT) * 16777216) +
       (CAST(PARSENAME(@IP,3) AS BIGINT) * 65536) +
       (CAST(PARSENAME(@IP,2) AS BIGINT) * 256) +
        CAST(PARSENAME(@IP,1) AS BIGINT) 
  AS BIGINT)

这就是它的样子供参考。

正如我所料,parsename 不是 redshift 中的函数,因此我的问题出现了。你们知道我可以达到相同结果的方法吗?

想通了:

( LEFT(ip_address, STRPOS(ip_address, '.')-1) * 16777216) + (LEFT(SUBSTRING(ip_address, LEN(LEFT(ip_address, STRPOS(ip_address, '.')+1))), LEN (ip_address) - LEN(LEFT(ip_address, STRPOS(ip_address, '.')-1)) - LEN(LEFT(REVERSE(ip_address), STRPOS(REVERSE(ip_address), '.')-1)) - 2) , STRPOS( SUBSTRING(ip_address, LEN(LEFT(ip_address, STRPOS(ip_address, '.')+1)), LEN(ip_address) - LEN(LEFT(ip_address, STRPOS(ip_address, '.')-1))) - LEN(LEFT(REVERSE(ip_address), STRPOS(REVERSE(ip_address), '.')-1)) - 2), '.')-1) * 65536) + (RIGHT( SUBSTRING(ip_address, LEN(LEFT( ip_address, STRPOS(ip_address, '.')+1)), LEN(ip_address) - LEN(LEFT(ip_address, STRPOS(ip_address, '.')-1)) - LEN(LEFT(REVERSE(ip_address), STRPOS( REVERSE(ip_address), '.')-1)) - 2), LEN(SUBSTRING(ip_address, LEN(LEFT(ip_address, STRPOS(ip_address, '.')+1)), LEN(ip_address) - LEN(LEFT (ip_address, STRPOS(ip_address, '.')-1)) - LEN(LEFT(REVERSE(ip_address), STRPOS(REVERSE(ip_address), '.')-1)) - 2)) - STRPOS(SUBSTRING(ip_address) , LEN(L EFT(ip_address, STRPOS(ip_address, '.')+1)), LEN(ip_address) - LEN(LEFT(ip_address, STRPOS(ip_address, '.')-1)) - LEN(LEFT(REVERSE(ip_address), STRPOS(REVERSE(ip_address), '.')-1)) - 2), '.') ) * 256) + (REVERSE( LEFT(REVERSE(ip_address), STRPOS(REVERSE(ip_address), '.')- 1) ) * 1 )

【问题讨论】:

“在 sql 中”->“在 Microsoft SQL Server 中”? “SQL”是查询语言,它不是产品。感谢您提到您正在使用 Redshift(ParAccel 的一个非常旧的 PostgreSQL 版本的专有分支),而不仅仅是说“PostgreSQL”。此外,最好发布您自己问题的答案,而不是尽可能编辑您的答案。 【参考方案1】:

哇,看到这个问题,我的眼睛都在流泪,不过我敢肯定,鉴于 Redshift 施加的限制,你没有太多选择。

我仍然很惊讶你必须做一些相当麻烦的事情。你不能至少创建一个或两个SQL 函数来整理它吗?还是Redshift连CREATE FUNCTION ... LANGUAGE sql都不支持?

作为参考,在适当的 PostgreSQL 中你会这样做:

select (split_part(ip, '.', 1)::bigint << 24) +
       (split_part(ip, '.', 2)::bigint << 16) +
       (split_part(ip, '.', 3)::bigint << 8) +
       (split_part(ip, '.', 4)::bigint);

或使用简单的 SQL 函数:

CREATE OR REPLACE FUNCTION inet_to_bigint(inet) AS $$
SELECT sum(split_part($1::text,'.',octetnum)::bigint << (32 - octetnum*8))
FROM generate_series(1,4) octetnum;
$$ LANGUAGE sql;

或者,几乎可以肯定最有效的是,滥用inet 数据类型的减法运算符:

SELECT (ip - '0.0.0.0')

(如果 Redshift 保留了 inet 数据类型,并且当 ParAccel 从 PostgreSQL 分叉时该功能早在 PostgreSQL 8.1 中存在,这个功能甚至可以在 Redshift 中使用)。

在旁注中,我很惊讶地发现在 PostgreSQL 中没有从 inet 定义到 bigint 的转换,因为我希望只能写 '127.0.0.1'::inet::bigint,这将是 CAST(CAST('127.0.0.1' AS inet) AS bigint) 的简写.

【讨论】:

Redshift 不支持函数或 IP 类型 +1 。 . .第一个解决方案似乎适用于 RedShift。【参考方案2】:

split_part(ip, '.', n) 应该这样做。

【讨论】:

我已经尝试使用@jakub,但是在使用亚马逊红移时,split_part 将无法在主节点之外工作。 @PatRickAllen 这些事情在原始问题中值得一提。 “我已经试过了……”。 Amazon 不提供在 Redshift 上测试东西的便捷方法(没有等效的 SQLFiddle,没有免费的测试服务器等),所以如果您标记问题 postgresql,人们会回复适用于 PostgreSQL 的答案。

以上是关于如何在 AMAZON REDSHIFT 中将 userip 转换为整数的主要内容,如果未能解决你的问题,请参考以下文章

如何减少在 Amazon Redshift 中将 pandas 数据帧写入表的时间

如何在 Amazon Redshift 中将列从字符串更改为日期?

无法在 Amazon Redshift 中将时间戳转换为日期

使用串联的 Amazon Redshift Pivot

在 Amazon Redshift 中提取部分字符串

如何在 Amazon Redshift 中使用 Hibernate 插入实体