【问题标题】:Netezza SQL convert VARCHAR to binary stringNetezza SQL 将 VARCHAR 转换为二进制字符串
【发布时间】:2015-12-15 20:45:08
【问题描述】:

我在 Netteza 中有一个存储为 VARCHAR 的位图。需要将 VARCHAR 转换为 Netezza 中的二进制字符串。

输入(Netezza col 值 - VARCHAR)= '0xFFFFFFFFFFFFFFFF'

期望的输出 (VARCHAR)->

'1111111111111111111111111111111111111111111111111111111111111111'

有没有办法使用 Netezza 查询来做到这一点?

我试过了

SELECT CAST('0xFFFFFFFFFFFFFFFF' AS VARBINARY(64) ); 

但这会引发错误

错误 [HY000] 错误:无法将类型“VARCHAR”转换为“VARBINARY”

【问题讨论】:

  • 您似乎想要将保存十六进制表示的 varchar 转换为 A)该十六进制值的二进制表示或 B)使用 ASCII 字符“0”的二进制表示的 varchar 表示和“1”。你能澄清一下你想要A还是B吗?
  • B 是我要找的。只是为了扩展这一点 - 最终我需要做的是如下 - 1 - 找到二进制字符串中第一个 1 的位置(在 '0xFFFFFFFFFFFFFFFF' 的情况下为 0 )。 2-在二进制字符串中找到 1 的计数(在 '0xFFFFFFFFFFFFFFFF' 的情况下为 64) - 从这个角度来看 B 可能就足够了
  • 看起来需要显式转换,但 this isn't supported by Netezza。所以看起来(对我来说)转换可能必须手动完成......
  • @SteveChambers - 您能否提供更多关于手动执行此操作的指导?
  • @user3206440 不完全确定去这里的最佳方式,但也许是用户定义的函数,它循环遍历字符串并建立二进制等价物?见this PDF

标签: sql netezza


【解决方案1】:

您可以将十六进制字符串转换为二进制数据并将其存储在 VARCHAR 或 VARBINARY 列中。我更喜欢 VARCHAR,因为可用于 VARBINARY 的 CAST 相当有限。

要将十六进制字符串转换为二进制并将其存储在 VARCHAR 中,请使用 SQL 扩展工具包提供的 hextoraw 函数。这包含在 Netezza 中,但必须由您的管理员配置并提供。

要将十六进制字符串转换为二进制并将其存储在 VARBINARY 中,请使用 Netezza 随附的 hex_to_binary 函数(在 v 7.2 中添加)。

drop table test_table if exists;
DROP TABLE
create table test_table (col1 varchar(50), col2 varbinary(50));
CREATE TABLE

insert into test_table values (hextoraw('464F4F'), hex_to_binary('464F4F'));
INSERT 0 1

select * from test_table;
 COL1 |   COL2
------+-----------
 FOO  | X'464F4F'
(1 row)

从那里您需要一个 UDF 来处理您想要执行的位计算。我已经整理了三个简单的 UDF,我相信它们会适合您的目的。

FirstBit 返回第一个非零位的位置。 BitCount 返回非零位的总数。 CharToBase2 将二进制值转换为 1 和 0 的 VARCHAR。

我认为前两个得到了你需要的最终结果,没有第三个,但如果你仍然想要它,它就在这里。

select firstbit(hextoraw('0000')), bitcount(hextoraw('0000')), chartobase2(hextoraw('0000'));
FIRSTBIT | BITCOUNT |   CHARTOBASE2
----------+----------+------------------
       -1 |        0 | 0000000000000000
(1 row)

select firstbit(hextoraw('0001')), bitcount(hextoraw('0001')), chartobase2(hextoraw('0001'));
 FIRSTBIT | BITCOUNT |   CHARTOBASE2
----------+----------+------------------
       15 |        1 | 0000000000000001
(1 row)

select firstbit(hextoraw('FFFF')), bitcount(hextoraw('FFFF')), chartobase2(hextoraw('FFFF'));
 FIRSTBIT | BITCOUNT |   CHARTOBASE2
----------+----------+------------------
        0 |       16 | 1111111111111111
(1 row)

这里是每个的来源。请注意,我是一个糟糕的 C++ 编码员,如果这是我的工作,我很可能会被解雇,所以请谨慎购买。

BitCount.cpp

#include "udxinc.h"
#include <string.h>

using namespace nz::udx;

class BitCount : public Udf
{
    public:
        static Udf* instantiate();

    ReturnValue evaluate()
    {
        StringArg* str = stringArg(0);
        int32 retval = 0;


        for(int i=0; i< str->length; i++)
                {

                for (int y=7; y>=0 ; y--)
                        {

                        if ((str->data[i] & (unsigned char)pow(2,y)) > 0)
                                {
                                        retval++;

                                }

                        }
                }

        NZ_UDX_RETURN_INT32(retval);
    }

};

Udf* BitCount::instantiate()
{
    return new BitCount;
}

FirstBit.cpp

#include "udxinc.h"
#include <string.h>

using namespace nz::udx;

class FirstBit : public Udf
{
    public:
        static Udf* instantiate();

    ReturnValue evaluate()
    {
        StringArg* str = stringArg(0);
        int32 retval = -1;


        for(int i=0; i< str->length; i++) {

                for (int y=7; y>=0 ; y--) {

                        if ((str->data[i] & (unsigned char)pow(2,y)) > 0)
                                {
                                        retval = i*8 + 7 - y;

                                }

                        if (retval > -1) break;
                }
                if (retval > -1)         break;
                }

        NZ_UDX_RETURN_INT32(retval);
    }

};

Udf* FirstBit::instantiate()
{
    return new FirstBit;
}

CharToBase2.cpp

#include "udxinc.h"
#include <string.h>

using namespace nz::udx;

class CharToBase2 : public Udf
{
    public:
        static Udf* instantiate();

    ReturnValue evaluate()
    {
        StringArg* str = stringArg(0);
        StringReturn* result = stringReturnInfo();
        result->size = str->length*8;
        //unsigned char stringbyte = 0 ;


        for(int i=0; i< str->length; i++)
                {


                  for (int y=7; y>=0 ; y-- )
                        {

                         if ((str->data[i] & (unsigned char)pow(2,y)) == 0) {
                                        result->data[i*8 + 7 - y] = '0'; }
                                else {
                                        result->data[i*8 + 7 - y] = '1';        }
                        }

                }

        NZ_UDX_RETURN_STRING(result);
    }

    uint64 calculateSize() const
    {
        return sizerStringSizeValue(sizerStringArgSize(0)*8);
    }
};

Udf* CharToBase2::instantiate()
{
    return new CharToBase2;
}

最后,这是我用来编译和安装每个脚本的脚本。

install_firstbit.sh 数据库名称

DB=$1
if [[ -z $DB ]]; then
 DB=$NZ_DATABASE
fi

if [[ -z $DB ]]; then
 print "Usage: install <database>"
 return 1
fi

export NZ_DATABASE="${DB}"

nzudxcompile FirstBit.cpp \
 --fenced \
 --sig   "FirstBit(varchar(any))" \
 --return  "integer" \
 --class  "FirstBit"

rm FirstBit.o_*

install_bitcount.sh 数据库名称

DB=$1
if [[ -z $DB ]]; then
 DB=$NZ_DATABASE
fi

if [[ -z $DB ]]; then
 print "Usage: install <database>"
 return 1
fi

export NZ_DATABASE="${DB}"

nzudxcompile BitCount.cpp \
 --fenced \
 --sig   "BitCount(varchar(any))" \
 --return  "integer" \
 --class  "BitCount"

rm BitCount.o_*

install_chartobase2.sh 数据库名称

DB=$1
if [[ -z $DB ]]; then
 DB=$NZ_DATABASE
fi

if [[ -z $DB ]]; then
 print "Usage: install <database>"
 return 1
fi

export NZ_DATABASE="${DB}"

nzudxcompile CharToBase2.cpp \
 --fenced \
 --sig   "CharToBase2(varchar(any))" \
 --return  "varchar(any)" \
 --class  "CharToBase2"

rm CharToBase2.o_*

【讨论】:

  • 太棒了 - 会试试这个!!
  • 除了将十六进制字符串转换为二进制字符串外,nzsql 应该可以工作。对于十六进制字符串到二进制字符串的转换,在您的带领下,我写了一个 UDF,希望它能帮助将 chartobase2(hextoraw('FFFF')) 压缩为 hextobin('FFFF') - 原生 CPP 代码有效,但是翻译后的 Netezza UDF 未经测试 - 无法访问现在一个。
【解决方案2】:

我认为您需要在 C 中定义一个 UDF,将其注册到数据库,然后在您的列上调用它。

我会先查看this answerthis one。在这两种情况下,您可能都必须去掉前面的 0x

【讨论】:

    【解决方案3】:

    遵循@ScottMcG 的建议 - 构建 UDF 以将十六进制字符串转换为二进制字符串。

    输入 -> 'F0F' 所需的输出 -> '11110000111'

    ---------HexToBin.cpp------

    #include "udxinc.h"
    #include <string.h>
    
    using namespace nz::udx;
    
    class HexToBin : public Udf
    {
        public:
            static Udf* instantiate();
    
        ReturnValue evaluate()
        {
            StringArg* str = stringArg(0);
            StringReturn* result = stringReturnInfo();
            result->size = str->length*4; // binary representation
            string quads[16] = {"0000", "0001", "0010", "0011", "0100", "0101",
                         "0110", "0111", "1000", "1001", "1010", "1011",
                         "1100", "1101", "1110", "1111"};
    
    
            // iterate through the string characters 
            for(int i = 0, len = str->length; i < len; i++)
            {
                char c = str->data[i];
                // concatenate quad to result->data based on character c
                if (c >= '0' && c <= '9') strcat(result->data,  quads[c - '0'].c_str());
                if (c >= 'A' && c <= 'F') strcat(result->data,  quads[10 + c - 'A'].c_str());
                if (c >= 'a' && c <= 'f') strcat(result->data,  quads[10 + c - 'a'].c_str());
    
            }        
    
            NZ_UDX_RETURN_STRING(result);
        }
    
        uint64 calculateSize() const
        {
            return sizerStringSizeValue(sizerStringArgSize(0)*4);
        }
    };
    
    Udf* HexToBin::instantiate()
    {
        return new HexToBin;
    }
    

    --------install_hextobin.sh DBNAME-------

    DB=$1
    if [[ -z $DB ]]; then
     DB=$NZ_DATABASE
    fi
    
    if [[ -z $DB ]]; then
     print "Usage: install <database>"
     return 1
    fi
    
    export NZ_DATABASE="${DB}"
    
    nzudxcompile HexToBin.cpp \
     --fenced \
     --sig   "HexToBin(varchar(any))" \
     --return  "varchar(any)" \
     --class  "HexToBin"
    
    rm HexToBin.o_*
    

    示例结果

    select hextobin('F0F');
       HEXTOBIN
    --------------
     111100001111
    (1 row)
    
    select hextobin('00F');
       HEXTOBIN
    --------------
     000000001111
    (1 row)
    
    select hextobin('F00');
       HEXTOBIN
    --------------
     111100000000
    (1 row)
    

    【讨论】:

    • 我对此进行了快速测试,并且必须进行两项更改才能使其作为 UDX 工作。我删除了 "result->data =""; " 并将结果赋值更改为如下形式: if (c >= '0' && c data, quads[c - '0'].c_str()); if (c >= 'A' && c data, quads[10 + c - 'A'].c_str()); if (c >= 'a' && c data, quads[10 + c - 'a'].c_str());如果您愿意,我可以更改您的答案,以更清晰的形式包含此内容。
    • @ScottMcG - 那太好了!
    猜你喜欢
    • 1970-01-01
    • 2021-02-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-02
    相关资源
    最近更新 更多