You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用github.com/jmoiron/sqlx扫描SQL返回值到结构体报错求助

解决sqlx插入后扫描返回值到结构体的问题

问题分析

你的代码存在两个关键问题导致报错:

  1. 参数传递方式错误:QueryRowx不支持直接传入结构体作为命名参数,必须使用sqlx提供的命名参数处理方法,否则会触发结构体类型不支持的错误。
  2. RETURNING子句格式错误:SQL中RETURNING (first_name, last_name)的写法会让PostgreSQL返回一个复合行类型,而非独立的列,导致StructScan无法正确映射到结构体字段。

修正后的代码

方法1:使用NamedQuery(推荐,更简洁)

package main

import (
    "log"

    "github.com/jmoiron/sqlx"
    _ "github.com/lib/pq"
)

const CreateUserSQL = `INSERT INTO users
(
    first_name,
    last_name
)
VALUES (
    :first_name,
    :last_name
)
RETURNING first_name, last_name
`

type User struct {
    FirstName string `db:"first_name"`
    LastName  string `db:"last_name"`
}

func main() {
    db, err := sqlx.Connect("postgres", "postgres://postgres:postgres@localhost:5432/postgres?sslmode=disable")
    if err != nil {
        log.Fatal(err)
    }
    defer db.Close()

    user := &User{
        FirstName: "John",
        LastName:  "Doe",
    }

    // 使用NamedQuery处理命名参数
    rows, err := db.NamedQuery(CreateUserSQL, user)
    if err != nil {
        log.Fatal(err)
    }
    defer rows.Close()

    // 读取返回的行并扫描到结构体
    if rows.Next() {
        err = rows.StructScan(user)
        if err != nil {
            log.Fatal(err)
        }
    }

    log.Printf("插入并返回的用户:%+v", user)
}

方法2:手动解析命名参数再执行

package main

import (
    "log"

    "github.com/jmoiron/sqlx"
    _ "github.com/lib/pq"
)

const CreateUserSQL = `INSERT INTO users
(
    first_name,
    last_name
)
VALUES (
    :first_name,
    :last_name
)
RETURNING first_name, last_name
`

type User struct {
    FirstName string `db:"first_name"`
    LastName  string `db:"last_name"`
}

func main() {
    db, err := sqlx.Connect("postgres", "postgres://postgres:postgres@localhost:5432/postgres?sslmode=disable")
    if err != nil {
        log.Fatal(err)
    }
    defer db.Close()

    user := &User{
        FirstName: "John",
        LastName:  "Doe",
    }

    // 将结构体解析为命名参数映射
    query, args, err := sqlx.Named(CreateUserSQL, user)
    if err != nil {
        log.Fatal(err)
    }

    // 把命名参数转换为PostgreSQL支持的$1、$2格式
    query = db.Rebind(sqlx.DOLLAR, query)

    // 执行查询并扫描结果
    err = db.QueryRowx(query, args...).StructScan(user)
    if err != nil {
        log.Fatal(err)
    }

    log.Printf("插入并返回的用户:%+v", user)
}

关键修正点说明

  • 修正RETURNING子句:去掉列名外的括号,让PostgreSQL返回独立的列,确保StructScan能通过结构体的db标签匹配字段。
  • 使用命名参数处理方法:
    • NamedQuery是sqlx专门用于处理命名参数查询的方法,直接接收结构体作为参数,自动解析映射到SQL中的:xxx占位符。
    • 手动解析方式通过sqlx.Named将结构体转为参数列表,再用db.Rebind适配PostgreSQL的参数格式,适合需要自定义SQL处理的场景。

内容的提问来源于stack exchange,提问作者dmbibishkin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 14:58:22