【问题标题】:sql: expected 3 destination arguments in Scan, not 1 in Golangsql: Scan 中预期的 3 个目标参数,而不是 Golang 中的 1 个
【发布时间】:2020-04-25 00:29:12
【问题描述】:

我正在编写一个通用代码来查询任何 RDS 表中的数据。我已经阅读了许多 StackOverflow 答案,但没有一个对我有用。我浏览了以下链接:-

我的第一个代码是

package main

import (
    "fmt"
)

type BA_Client struct {
    ClientId    int    `json:ClientId;"`
    CompanyName string `json:CompanyName;"`
    CreateDate  string `json:CreateDate;"`
}

func main() {

    conn, _ := getConnection() // Det database connection

    query := `select * from IMBookingApp.dbo.BA_Client
              ORDER BY
                ClientId ASC
              OFFSET 56 ROWS
              FETCH NEXT 10 ROWS ONLY ;`

    var p []byte
    err := conn.QueryRow(query).Scan(&p)
    if err != nil {
        fmt.Println("Error1", err)
    }

    fmt.Println("Data:", p)

    var m BA_Client
    err = json.Unmarshal(p, &m)
    if err != nil {
        fmt.Println("Error2", err)
    }

}

我的第二个代码是

conn, _ := getConnection()
query := `select * from IMBookingApp.dbo.BA_Client__c
          ORDER BY
            ClientId__c ASC
          OFFSET 56 ROWS
          FETCH NEXT 10 ROWS ONLY ;`

rows, err := conn.Query(query)
if err != nil {
    fmt.Println("Error:")
    log.Fatal(err)
}

println("rows", rows)

defer rows.Close()

columns, err := rows.Columns()
fmt.Println("columns", columns)

if err != nil {
    panic(err)
}

for rows.Next() {
    receiver := make([]*string, len(columns))

    err := rows.Scan(&receiver )
    if err != nil {
        fmt.Println("Error reading rows: " + err.Error())
    }
    fmt.Println("Data:", p)

    fmt.Println("receiver", receiver)
}

使用这两个代码,我得到与以下相同的错误

sql: expected 3 destination arguments in Scan, not 1

可能是因为我使用的是 SQL Server 而不是 MySQL?感谢是否有人可以帮助我找到问题。

【问题讨论】:

    标签: sql sql-server go


    【解决方案1】:

    如果您想使用输入切片进行行扫描,请使用可变参数 3 点表示法 ... 将切片转换为单独的参数,如下所示:

    err := rows.Scan(receiver...)
    

    您的(在这种情况下为三个)列,使用可变参数将有效地扩展如下:

    // len(receiver) == 3
    err := rows.Scan(receiver[0], receiver[1], receiver[2])
    

    编辑

    SQL Scan 方法参数值的类型必须为interface{}。所以我们需要一个中间切片。例如:

    is := make([]interface{}, len(receiver))
    for i := range is {
        is[i] = receiver[i]
    
        // each is[i] will be of type interface{} - compatible with Scan()
        // using the underlying concrete `*string` values from `receiver`
    }
    
    // ...
    
    err := rows.Scan(is...)
    
    // `receiver` will contain the actual `*string` typed items
    

    【讨论】:

    • 感谢您的回答。但它给了我这个错误 - cannot use receiver (type []*string) as type []interface {} in argument to rows.Scan
    • @RahulSatal 更新了答案以包括中间 interface{} 切片步骤。
    • 您发布的问题使用了receiver := make([]*string, len(columns)) - 所以这是一个指针。您的游乐场链接正在使用 []string 即非指针。所以要么使用指针支持切片。或者把我上面的那行改成is[i] = &receiver[i]
    • 是的,它奏效了。非常感谢,@Colminator。我为此苦苦挣扎了 3 天:)
    • 您可以使用**string - 处理NULL,但我建议使用sql.NullString 来避免样板零检查,因此使用该类型:receiver := make([]sql.NullString, len(columns)) 结合@987654335 @
    【解决方案2】:

    在第二个例子中试试这个(接收器前面没有&符号):

    err := rows.Scan(receiver)
    

    receiver*string 已经是引用类型。无需添加其他引用。

    【讨论】:

    • 我也试过这个,但它也不适合我。你对我还有什么建议吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-18
    • 2021-11-08
    • 1970-01-01
    • 1970-01-01
    • 2021-01-10
    • 2023-01-03
    相关资源
    最近更新 更多