【问题标题】:How to get uuid of last inserted row using sqlx in postgres如何在postgres中使用sqlx获取最后插入行的uuid
【发布时间】:2021-04-12 03:23:10
【问题描述】:

我正在使用这样的 SQLx 在表中插入一些数据

func (*RideRepositoryImpl) insert(entity interface{}, tx persistence.Transaction) (sql.Result, error) {
    ride := entity.(*model.Ride)

    placeHolders := repository.InsertPlaceholders(len(rideColumns))
    sql := fmt.Sprintf("INSERT INTO %s(%s) VALUES(%s)", TableName, strings.Join(Columns, ","), placeHolders)
    return tx.Exec(sql, ride.ID.String(), ride.DeviceIotID, ride.VehicleID.String(), ride.UserID.String(),ride.AdditionComments)
}

并像这样调用这个函数

func (p *RideRepositoryImpl) Save(ride *model.Ride, tx persistence.Transaction) error {
    return repository.Save(ride, p.insert, tx)

现在我想在保存此记录后立即获取已保存记录的 UUID。有什么干净的方法可以立即做到这一点吗?

【问题讨论】:

    标签: postgresql go sqlx


    【解决方案1】:

    PostgreSQL 对此有 RETURNING 子句。

    有时从修改后的行中获取数据很有用 正在被操纵。 INSERTUPDATEDELETE 命令 都有一个可选的RETURNING 子句支持这一点。用于 RETURNING 避免执行额外的数据库查询来收集 数据,并且在本来很难的情况下尤其有价值 可靠地识别修改的行。

    // add the RETURNING clause to your INSERT query
    sql := fmt.Sprintf("INSERT INTO %s(%s) VALUES(%s) RETURNING <name_of_uuid_column>", TableName, strings.Join(Columns, ","), placeHolders)
    
    // use QueryRow instead of Exec
    row := tx.QueryRow(sql, ride.ID.String(), ride.DeviceIotID, ride.VehicleID.String(), ride.UserID.String(),ride.AdditionComments)
    
    // scan the result of the query
    var uuid string
    if err := row.Scan(&uuid); err != nil {
        panic(err)
    }
    
    // ...
    

    有关与 RETURNING 相关的其他 INSERT 特定信息,您可以转到 INSERT 文档并使用 CTRL/CMD+F 在页面中搜索“返回”。


    此外,如果您需要您的函数仍返回一个 sql.Result 值以满足某些要求,那么您可以返回您自己的实现。

    var _ sql.Result = sqlresult{} // compiler check
    
    type sqlresult struct { lastid, nrows int64 }
    
    func (r sqlresult) LastInsertId() (int64, error) { return r.lastid, nil }
    func (r sqlresult) RowsAffected() (int64, error) { return r.nrows, nil }
    
    func (*RideRepositoryImpl) insert(entity interface{}, tx persistence.Transaction) (sql.Result, error) {
        ride := entity.(*model.Ride)
    
        placeHolders := repository.InsertPlaceholders(len(rideColumns))
        sql := fmt.Sprintf("INSERT INTO %s(%s) VALUES(%s) RETURNING <name_of_uuid_column>", TableName, strings.Join(Columns, ","), placeHolders)
        row := tx.QueryRow(sql, ride.ID.String(), ride.DeviceIotID, ride.VehicleID.String(), ride.UserID.String(),ride.AdditionComments)
        if err := row.Scan(&ride.<NameOfUUIDField>); err != nil {
            return nil, err
        }
        return sqlresult{0, 1}, nil
    }
    

    【讨论】:

    • 感谢您的回答先生,您可以看到我的插入功能有一个问题我想返回(sql.Result, error) ,所以在这种情况下,我将返回(sql.Result, error)
    • 您为什么要这样做?你需要它做什么?如果你需要它来满足一个接口,那么只需返回一个nilsql.Result
    • 测试已在此返回的基础上编写。就像它在应用程序中为 CRUD 预先实现的架构一样,我需要 (sql.Result, error) 作为回报,默认返回 tx.Exec
    • @Ninja sql.Result 是一个接口,你可以随时返回你自己的虚拟实现,非常简单。
    • 我无法从QueryRow 得到相同的结果?因为它可能会改变其他插入场景
    猜你喜欢
    • 2019-05-28
    • 1970-01-01
    • 1970-01-01
    • 2021-08-21
    • 2019-05-10
    • 2011-09-23
    • 1970-01-01
    • 2019-07-07
    • 2019-11-21
    相关资源
    最近更新 更多