Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/go/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在不替换Golang中以前的行的情况下将最后一行sql追加到列表中_Go - Fatal编程技术网

如何在不替换Golang中以前的行的情况下将最后一行sql追加到列表中

如何在不替换Golang中以前的行的情况下将最后一行sql追加到列表中,go,Go,这段代码提供了一个正确的JSON输出[{},{}],但是每一行都会被追加并替换前面的所有行,因此结果只显示最后一行的副本 var rows *sql.Rows rows, err = db.Query(query) cols, _ := rows.Columns() colnames, _ := rows.Columns() vals := make([]interface{}, len(cols)) for i, _ := range cols { vals[i] = &col

这段代码提供了一个正确的JSON输出[{},{}],但是每一行都会被追加并替换前面的所有行,因此结果只显示最后一行的副本

var rows *sql.Rows
rows, err = db.Query(query)
cols, _ := rows.Columns()
colnames, _ := rows.Columns()
vals := make([]interface{}, len(cols))

for i, _ := range cols {
   vals[i] = &cols[i]
}

m := make(map[string]interface{})
 
for i, val := range vals {
  m[colnames[i]] = val
}
    
list := make([]map[string]interface{}, 0)
for rows.Next() {
err = rows.Scan(vals...)
   list = append(list, m)
}
json, _ := json.Marshal(list)
fmt.Fprintf(w,"%s\n", json)
这是在后台通过行循环发生的情况:

循环1:{“ID”:“1”,“NAME”:“John}

循环2:{“ID”:“2”,“NAME”:“Jane Doe”}{“ID”:“2”,“NAME”:“Jane Doe”}

循环3:{“ID”:“3”,“NAME”:“donaldduck”}{“ID”:“3”,“NAME”:“donaldduck”}{“ID”:“3”,“NAME”:“donaldduck”}

Scan获取正确的值,但它附加并替换所有以前的值

最终输出如下

[{“ID”:“3”,“NAME”:“Donald Duck”},{“ID”:“3”,“NAME”:“Donald Duck”},{“ID”:“3”,“NAME”:“Donald Duck”}]

但应该是这样的:

[{“ID”:“1”,“NAME”:“John Doe”},{“ID”:“2”,“NAME”:“Jane Doe”},{“ID”:“3”,“NAME”:“Donald Duck”}]

我做错了什么


您可以对此投反对票,但请解释原因。我仍然是Golang的新手,希望学习。

我修复了它,并用评论解释了您的错误:

// 1. Query
var rows *sql.Rows
rows, err = db.Query(query)
cols, _ := rows.Columns()

// 2. Iterate
list := make([]map[string]interface{}, 0)
for rows.Next() {
    vals := make([]interface{}, len(cols))
    for i, _ := range cols {
        // Previously you assigned vals[i] a pointer to a column name cols[i].
        // This meant that everytime you did rows.Scan(vals),
        // rows.Scan would see pointers to cols and modify them
        // Since cols are the same for all rows, they shouldn't be modified.

        // Here we assign a pointer to an empty string to vals[i],
        // so rows.Scan can fill it.
        var s string
        vals[i] = &s

        // This is effectively like saying:
        // var string1, string2 string
        // rows.Scan(&string1, &string2)
        // Except the above only scans two string columns
        // and we allow as many string columns as the query returned us — len(cols).
    }

    err = rows.Scan(vals...)

    // Don't forget to check errors.
    if err != nil {
        log.Fatal(err)
    }

    // Make a new map before appending it.
    // Remember maps aren't copied by value, so if we declared
    // the map m outside of the rows.Next() loop, we would be appending
    // and modifying the same map for each row, so all rows in list would look the same.
    m := make(map[string]interface{})
    for i, val := range vals {
        m[cols[i]] = val
    }
    list = append(list, m)
}

// 3. Print.
b, _ := json.MarshalIndent(list, "", "\t")
fmt.Printf("%s\n", b)
别担心,当我还是初学者的时候,这对我来说也是很难理解的

现在,有趣的事情:

var list []map[string]interface{}
rows, err := db.Queryx(query)
for rows.Next() {
    row := make(map[string]interface{})
    err = rows.MapScan(row)
    if err != nil {
      log.Fatal(err)
    }
    list = append(list, row)
}

b, _ := json.MarshalIndent(list, "", "\t")
fmt.Printf("%s\n", b)
这和上面的代码是一样的,但是有点简单,不是吗

sqlx是
数据库/sql
之上的一个扩展,具有直接将行扫描到映射和结构的方法,因此您不必手动执行该操作

我认为你的模型作为一个结构看起来更好:

type Person struct {
    ID int
    Name string
}

var people []Person
rows, err := db.Queryx(query)
for rows.Next() {
    var p Person
    err = rows.StructScan(&p)
    if err != nil {
        log.Fatal(err)
    }
    people = append(people, p)
}

你不这么认为吗?

你一次又一次地在列表中添加m,而没有修改m。为什么你希望切片元素之后会有所不同?哦,我现在明白了。你似乎认为m是以某种方式被复制的。这是a)不是真的,b)不会改变任何东西,因为映射存储指针。因此复制映射会复制指针,但y仍然会指向相同的值。但是扫描会更改指向的值,而不是指针;地址不会更改。长话短说,
为每一行创建一个新映射。谢谢!它工作得很好。我知道sqlx,但没有修复base64到字符串的转换。数值显示不正确。使用结构是最简单的st resort,因为我经常不知道结构。但这似乎是个问题。此代码无法处理空值。它会崩溃。如何解决此问题?请尝试将
vals[I]=&s
替换为
vals[I]=&&s
,但我不确定它可能只适用于可为空的列。我不好,尝试不使用&at,并将之前的行更改为
var s**string
@moshe revah会崩溃。甚至不会为空