Redshift 返回一个 []uint8 而不是整数,在它们之间转换会返回不正确的值

Posted

技术标签:

【中文标题】Redshift 返回一个 []uint8 而不是整数,在它们之间转换会返回不正确的值【英文标题】:Redshift returns a []uint8 instead of an integer, converting between them returns incorrect values 【发布时间】:2019-03-04 17:44:27 【问题描述】:

我有一项服务,它接受 SQL 查询,使用数据库/sql 驱动程序在 Amazon Redshift 上运行查询。但是,我无法将结果转换为结构,因为查询是各种表上的大数据任务,而不是在此服务中创建的。所以我必须返回一个“松散”的数据结构。我正在解析返回到 JSON 中的数据并将其存储在 S3 中。

但是,我在返回的数据类型方面遇到了一些奇怪的问题。对于数字列,查询返回 uint8 的映射而不是数值。我知道这是因为数据库驱动程序无法对将其转换为什么有意见,因为它可能不精确。但我似乎也无法在 []uint8 和整数之间进行转换。

这是我查询数据库的代码:

// Execute executes SQL commands
func (r *Runner) Execute(query string, args ...interface) (types.Results, error) 
    var results types.Results
    rows, err := r.db.Query(query, args...)
    if err != nil 
        return results, err
    

    columns, _ := rows.Columns()
    colNum := len(columns)

    values := make([]interface, colNum)
    for i := range values 
        var ii interface
        values[i] = &ii
    

    for rows.Next() 
        rows.Scan(values...)
        result := make(types.Result)
        for i, colName := range columns 
            rawValue := *(values[i].(*interface))
            if reflect.TypeOf(rawValue).String() == "[]uint8" 
                byteVal := rawValue.([]byte)
                val := Intfrombytes(byteVal)
                log.Println("Converted:", val)
            
            result[colName] = rawValue
        
        results = append(results, result)
    
    return results, nil

我创建了以下函数来尝试在[]uint8uint32 之间进行转换。

func Intfrombytes(bytes []uint8) uint16 
    bits := binary.LittleEndian.Uint16(bytes)
    return bits

但是,如果我将 200 插入到该表中,我会返回 12339。一般来说,这种方法感觉很不稳定。我怀疑我使用 Go 的决定,因为我正在处理未定义的松散数据结构。

是否有更好的通用查询方法(例如我的示例),或者有什么方法可以将我的数字结果转换为整数?

【问题讨论】:

Postgres 表具有严格定义的架构,为什么不能将列映射到明确定义的类型? @Adrian 因为该服务支持基于 Web 的 SQL 编辑器,该编辑器接受大量 SQL 查询并返回 JSON 数据。它用于加载不同的表。目前数字正在转换为 []uint8,json.Marshal 将其转换为 base64 字符串。所以在结果中,所有数字都以 base64 的形式返回!它不是一个典型的建模和结构服务,它做的是通用的数据库工作并返回结果。 你试过 bigendian 吗?至少看起来这就是lib/pq 正在使用的东西。 github.com/lib/pq/search?q=endian&unscoped_q=endian 我认为您实际上可能正在解释一个字符串 ([]uint8 == []byte)。见play.golang.org/p/Rfpey2NPiI7 @EwanValentine 我明白了,“数字列”是指任意精度类型numeric?或integer 类型,或real? 【参考方案1】:

实际上,我认为您可能正在解释一个字符串 ([]uint8 == []byte)。见https://play.golang.org/p/Rfpey2NPiI7

originalValue := []uint80x32, 0x30, 0x30 // "200"
bValue := []byte(originalValue) // byte is a uint8 anyway
fmt.Printf("Converted to uint16: %d\n", binary.LittleEndian.Uint16(bValue))
fmt.Printf("Actual value: %s", string(bValue))

在处理pq 和一些加密代码时,这让我很痛苦。

【讨论】:

答案必须完整,没有以下链接。为此,我将您的答案代码的实质内容直接复制到了答案中,以免您的答案被删除。

以上是关于Redshift 返回一个 []uint8 而不是整数,在它们之间转换会返回不正确的值的主要内容,如果未能解决你的问题,请参考以下文章

当我们使用 Glue 将数据从 DocumentDb 转储到 Redshift 时,从 Redshift 获取字符串而不是数组

亚马逊 - Redshift:给定日期的周数错误

redshift 返回的结果集是不是支持重置迭代器?

接口转换:interface {}是int64,而不是[] uint8

Amazon Redshift:是不是可以返回多个结果集?

Redshift JDBC DatabaseMetaData.getDatabaseMajorVersion() 是不是返回最新值?