将一个 SQL 查询 sqlx.Rows 扫描到 Golang 中的嵌套结构中。

3

我有以下三个表:

create table A (
  a_id     varchar(256) not null unique,
  a_name   varchar(256)
);

create table B (
  b_id     varchar(256) not null,
  b_a_id   varchar(256) not null,
  b_name   varchar(256),
  FOREIGN KEY (b_a_id) REFERENCES a (a_id)
);

create table C (
  c_id     varchar(256) not null,
  c_a_id   varchar(256) not null,
  c_name   varchar(256),
  FOREIGN KEY (c_a_id) REFERENCES a (a_id)
);

insert into A(a_id, a_name) values('1234', 'a_name_1');

insert into B(b_id, b_a_id, b_name) values('B1','1234', 'b_name_1');
insert into B(b_id, b_a_id, b_name) values('B2','1234', 'b_name_2');

insert into C(c_id, c_a_id, c_name) values('C1','1234', 'c_name_1');
insert into C(c_id, c_a_id, c_name) values('C2','1234', 'c_name_2');
insert into C(c_id, c_a_id, c_name) values('C3','1234', 'c_name_3');


我在golang中有以下structs:
type A struct {
     a_id   string    `db:"a_id"`
     a_name string    `db:"a_name"`
     b      *B        `db:"b"`
     c      *C        `db:"c"`
}

type B struct {
    b_id    string     `db:"b_id"`
    b_name  string     `db:"b_name"`
    b_a_id  string     `db:"b_a_id"`
}

type C struct {
    c_id    string     `db:"c_id"`
    c_name  string     `db:"c_name"`
    c_a_id  string     `db:"c_a_id"`
}

我想要扫描执行联接查询后得到的行:

SELECT * from A INNER JOIN B ON a_id=b_a_id inner join C on c_a_id=a_id;

使用Golang中的rows.StructScan()将其转换为Struct A,但我无法做到。我该如何将联接查询结果扫描到嵌套结构中,而且我不想逐个扫描每一列,因为联接查询的结果会有很多列。

2个回答

0
请看一下这个答案 Stackoverflow 使用一个轻量级的库 Carta 可以将 SQL 结果映射到嵌套结构体中。

0
经过一些调查,我想出了一个解决方案,这个方案对你也适用。首先,让我介绍一下可行的代码,然后我会解释相关部分:
package main

import (
    "fmt"

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

type A struct {
    Id   string `db:"a_id"`
    Name string `db:"a_name"`
    B
    C
}

type B struct {
    Id   string `db:"b_id"`
    AId  string `db:"b_a_id"`
    Name string `db:"b_name"`
}

type C struct {
    Id   string `db:"c_id"`
    AId  string `db:"c_a_id"`
    Name string `db:"c_name"`
}

func main() {
    db, err := sqlx.Open("postgres", "host=localhost user=postgres password=postgres dbname=postgres port=5432 sslmode=disable")
    if err != nil {
        panic(err)
    }
    defer db.Close()

    a := []A{}
    rows, err := db.Queryx("SELECT * from A INNER JOIN B ON a_id=b_a_id inner join C on c_a_id=a_id;")
    if err != nil {
        panic(err)
    }
    defer rows.Close()

    for rows.Next() {
        var record A
        if err := rows.StructScan(&record); err != nil {
            panic(err)
        }
        a = append(a, record)
    }

    if err := rows.Err(); err != nil {
        panic(err)
    }

    for _, v := range a {
        fmt.Println(v)
    }
}

结构体定义

在这里,我通过将BC嵌入到A结构体中来修复了结构体的定义。此外,只要它们与其他结构体不冲突(例如,在所有三个结构体中都有Id字段是完全安全的),我还修复了名称。

获取数据

另一个相关部分是从Postgres获取数据。在这里,您必须使用Queryx方法,并向其提供您正确编写的SQL查询。
但是,在处理多行数据时(如我们的情况),您应该使用database/sql包提供的方法。 NextErr是不言自明的,因此我不会花时间解释它们。
StructScan是执行操作的方法。它将当前查询放入名为record的循环作用域变量中,类型为A(即我们的父结构体)。

如果您尝试此代码,它也应该适用于您,如果不行,请告诉我!


嗨@Abinaya Hariharan,你解决了吗? - ossan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接