不支持的扫描:SQL UUID 数组

huangapple go评论82阅读模式
英文:

Unsupported Scan: SQL UUID Array

问题

我正在尝试从 PostgreSQL 数据库中获取一个 UUID 数组,但是出现了以下错误:

sql: 在索引为 0 的列上扫描错误:不支持的扫描,将 driver.Value 类型的 []uint8 存储到类型为 *[]string 的变量中

获取单个 UUID 没有问题,但是当它是一个数组时,Scan 函数将元素的类型推断为 uint8

是否有解决这个问题的方法?或者我应该重新考虑我的数据库设计?

代码:

func FetchListIdsForUser(id string, db *sql.DB) ([]string, error) {

    // 存储结果的变量

    var (
        lists []string
    )


    // 准备语句

    stmt, err := db.Prepare("select lists from users where object_id = $1")
    if err != nil {
        formattedError := er.New("FetchListIdsForUser SQL Select: " + err.Error())
        log.Println(formattedError)
        return nil,formattedError
    }
    defer stmt.Close()


    // 执行查询

    rows, err := stmt.Query(id)
    if err != nil {
        formattedError := er.New("FetchListIdsForUser SQL Query: " + err.Error())
        log.Println(formattedError)
        return nil,formattedError
    }

    defer rows.Close()


    // 遍历每一行

    for rows.Next() {

        // 扫描:这是出错的地方

        err := rows.Scan(&lists)
        if err != nil {
            formattedError := er.New("FetchListIdsForUser SQL Scan: " + err.Error())
            log.Println(formattedError)
            return nil,formattedError
        }
        return lists,nil
    }

    err = rows.Err()
    if err != nil {
        formattedError := er.New("FetchListIdsForUser: " + id + " Does Not Exist")
        log.Println(formattedError)
        return nil,formattedError
    }
    return nil,er.New("FetchListIdsForUser: " + id + " Does Not Exist")
}
英文:

I am trying to get an array of UUID from a PostgreSQL DB, this gives the following error:

sql: Scan error on column index 0: unsupported Scan, storing driver.Value type []uint8 into type *[]string

Fetching a single UUID is no problem, but when it is an array, the Scan function infers the type of the elements as uint8.

Is there a workaround / solution for this? Or should I rethink my DB?

Code :

func FetchListIdsForUser(id string, db *sql.DB) ([]string, error) {

        // where the results will be stored

		var (
			lists []string
		)


        // statement prep

		stmt, err := db.Prepare("select lists from users where object_id = $1")
			if err != nil {
			formattedError := er.New("FetchListIdsForUser SQL Select: " + err.Error())
			log.Println(formattedError)
			return nil,formattedError
		}
		defer stmt.Close()


        // query happening

		rows, err := stmt.Query(id)
		if err != nil {
			formattedError := er.New("FetchListIdsForUser SQL Query: " + err.Error())
			log.Println(formattedError)
			return nil,formattedError
		}

        defer rows.Close()


        // for each row

		for rows.Next() {

            // scan : this is where the error happens.

			err := rows.Scan(&lists)
			if err != nil {
				formattedError := er.New("FetchListIdsForUser SQL Scan: " + err.Error())
				log.Println(formattedError)
				return nil,formattedError
			}
			return lists,nil
		}

        err = rows.Err()
		if err != nil {
			formattedError := er.New("FetchListIdsForUser: " + id + " Does Not Exist")
			log.Println(formattedError)
			return nil,formattedError
		}
		return nil,er.New("FetchListIdsForUser: " + id + " Does Not Exist")
}

答案1

得分: 1

你的代码可以简化很多:

func FetchListIdsForUser(id string, db *sql.DB) ([]string, error) {
    rows, err := db.Query("SELECT unnest(lists) FROM users WHERE object_id = $1", id)
    if err != nil { 
        formattedError := errors.New("FetchListIdsForUser SQL Query: " + err.Error())
        return nil, formattedError
    }

    defer rows.Close()

    var lists []string
    var list string

    for rows.Next() {
        // scan every item of the array and append it to lists
        err := rows.Scan(&list)
        if err != nil {
            formattedError := errors.New("FetchListIdsForUser SQL Scan: " + err.Error())
            return nil, formattedError
        }
        lists = append(lists, list)
    }

    if lists == nil {
        // no rows returned
        formattedError := errors.New("FetchListIdsForUser: " + id + " Does Not Exist")
        return nil, formattedError
    }

    return lists, nil
}
  • db.Query() 会为你准备(并缓存)语句,不需要手动执行。
  • 我在 select 语句中添加了 unnest(lists)。这将为数组中的每个元素生成一行。
  • 在循环中,我们逐个扫描每个元素并将其追加到 lists 中。

此外,这个驱动程序可以直接支持扫描数组。

英文:

Your code can be simplified a lot:

func FetchListIdsForUser(id string, db *sql.DB) ([]string, error) {

        rows, err := db.Query("SELECT unnest(lists) FROM users WHERE object_id = $1", id)
        if err != nil { 
            formattedError := errors.New("FetchListIdsForUser SQL Query: " + err.Error())
            return nil, formattedError
        }

        defer rows.Close()

        var lists []string
        var list string

        for rows.Next() {
            // scan every item of the array and append it to lists
            err := rows.Scan(&list)
            if err != nil {
                formattedError := errors.New("FetchListIdsForUser SQL Scan: " + err.Error())
                return nil,formattedError
            }
            lists = append(lists, list)
        }

        if lists == nil {
            // no rows returned
            formattedError := errors.New("FetchListIdsForUser: " + id + " Does Not Exist")
            return nil, formattedError
        }

        return lists, nil
}
  • db.Query() will prepare (and cache) the statement for you. There's no need to do that manually.
  • I added unnest(lists) to the select statement. This will produce one row for every element in the array.
  • In the for loop, we scan every element individually and append it to lists.

Also, this driver supports scanning arrays out of the box.

huangapple
  • 本文由 发表于 2016年3月18日 19:25:14
  • 转载请务必保留本文链接:https://go.coder-hub.com/36083147.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定