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

时间:2013-06-28 20:19:54

标签: sql postgresql amazon-redshift

刚刚开始玩游戏并测试亚马逊的红移。我需要做的一件事就是我可以在sql中轻松完成将userip更改为整数。这是在mssql中使用标量函数完成的,该函数使用parsename来分解ip numbres和它们的常数。

 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(左) (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)

2 个答案:

答案 0 :(得分:2)

哇,看到那个问题,我的目光正在浇水,不过考虑到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')

(如果他们保留了inet数据类型,并且如果此功能在PostgreSQL 8.1中存在,当ParAccel从PostgreSQL派生时,这个功能甚至可以在Redshift中工作。

另一方面,我很惊讶地看到在PostgreSQL中没有从inet到bigint定义的强制转换,因为我希望能够写出'127.0.0.1'::inet::bigint,这将是速记CAST(CAST('127.0.0.1' AS inet) AS bigint)

答案 1 :(得分:1)

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