Go中的数据库继承

huangapple go评论160阅读模式
英文:

Database Inheritance in Go

问题

我有一个情况,我有一个基本类型,让我们称之为Pet类型(不是真实类型,只是一个合适的例子),以及6个这个类型的不同变体,它们都可以有自己的独立字段。假设它们分别是不同类型的宠物,比如DogCatBird等。现在它们都组织在同一个名为pets的表中,但我认为将每种类型分别放入自己的表中(dogscatsbirds等),然后从主表pets继承字段会更有益。需要明确的是,我的每个子表都有独特的字段,不适用于任何其他子类型。

我正在使用database/sql,并且像这样查询数据:

var getPetsQuery = fmt.Sprintf(`SELECT %v FROM pets`)

func (tx *Tx) GetPets() (pets []*model.Pet, err error) {
    return tx.petQueryRow(getPetsQuery)
}

func (tx *Tx) petQueryRow(query string, args ...interface{}) (pets []*model.Pet, err error) {
    rows, err := tx.Query(query, args...)
    if err != nil {
        return nil, errors.Stacktrace(PetQueryFailedErr(err))
    }
    defer rows.Close()

    for rows.Next() {
        pet := &model.Pet{}
        err = rows.Scan(
            &pet.Id,
            &pet.Uid,
            &pet.Created,
            &pet.Type,
            &pet.LegCount,
        )
        results = append(results, pet)
    }

    err = rows.Err()
    if err != nil {
        return nil, errors.Stacktrace(PetQueryFailedErr(err))
    }
    return results, err
}

我的问题是,使用这个系统,如果我想查询所有类型的宠物列表,我该如何在单个查询中加载每个个别子类型表的额外数据?还是我需要先加载一个宠物列表,然后逐个查询额外的数据?

英文:

I have a situation where I have a base type, let's call it the Pet type (not the real type but an apt example), and 6 underlying variants of this type that all could have their own individual fields. Let's say they are each different types of pets, like Dog, Cat, Bird, etc. Right now they are all organized in the same table called pets, but I think I would benefit from breaking each type out into their own table(dogs, cats, birds, etc) and then inheriting the fields from the main pets table. To be clear, each of my child tables have unique fields that don't apply to any of the other subtypes.

I'm using database/sql, and I query for data like so:

var getPetsQuery = fmt.Sprintf(`SELECT %v FROM pets`)

func (tx *Tx) GetPets() (pets []*model.Pet, err error) {
	return tx.petQueryRow(getPetsQuery)
}

func (tx *Tx) petQueryRow(query string, args ...interface{}) (pets []*model.Pet, err error) {
	rows, err := tx.Query(query, args...)
    if err != nil {
    	return nil, errors.Stacktrace(PetQueryFailedErr(err))
    }
    defer rows.Close()
    
    for rows.Next() {
    	pet := &model.Pet{}
    	err = rows.Scan(
    		&pet.Id,
    		&pet.Uid,
    		&pet.Created,
    		&pet.Type,
            &pet.LegCount,
    	)
    	results = append(results, pet)
    }
    
    err = rows.Err()
    if err != nil {
    	return nil, errors.Stacktrace(PetQueryFailedErr(err))
    }
    return results, err
}

My question is, using this system, if I wanted to query for a list of pets of all types, how would I go about loading the extra data from each individual subtype table in a single query? Or would I need to load a list of pets first and then query for the additional data individually?

答案1

得分: 2

这不是关于Go的问题,而是关于Postgres的问题。好消息是,通过使用UNION,Postgres应该可以让你实现你想要的功能。你只需要将所有的表使用UNION合并到一个查询中。

SELECT id,
       uid,
       created,
       legcount,
       wingcount,
       NULL AS fincount
FROM snakes
UNION
SELECT id,
       uid,
       created,
       legcount,
       NULL AS wingcount,
       NULL AS fincount
FROM dogs
SELECT id,
       uid,
       created,
       NULL AS legcount,
       NULL AS wingcount,
       fincount
FROM fish

关键是,为了使UNION起作用,每个子查询必须具有完全相同的列,所以你需要填充NULL列(如示例中的NULL AS fincount等)。

如果你想对此进行查询,你可以将所有内容包装在一个子查询中以方便操作:

SELECT * FROM (
    SELECT id,
    <snip>
    UNION
    SELECT id,
    <snip>
)
WHERE legcount = 3;
英文:

This isn't a question about Go, but rather one about Postgres. The good news is, Postgres should let you do what you want with the use of UNION. You'll just need to UNION all of your tables together into a single query.

SELECT id,
       uid,
       created,
       legcount,
       wingcount,
       NULL AS fincount
FROM snakes
UNION
SELECT id,
       uid,
       created,
       legcount,
       NULL AS wingcount,
       NULL AS fincount
FROM dogs
SELECT id,
       uid,
       created,
       NULL AS legcount,
       NULL AS wingcount,
       fincount
FROM fish

The key is that for a UNION to work, each subquery must have the exact same columns, so you'll need to fill in NULL columns (as demonstrated with NULL AS fincount, etc).

If you want to perform a query on this, you can wrap it all in a subquery for convenience:

SELECT * FROM (
    SELECT id,
    &lt;snip&gt;
    UNION
    SELECT id,
    &lt;snip&gt;
)
WHERE legcount = 3;

huangapple
  • 本文由 发表于 2017年7月14日 03:12:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/45089229.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定