Go:在SQL连接结果

时间:2017-07-02 19:41:31

标签: go

我正在为位置和事件(在这些位置发生)运行连接的SQL查询。在结果中,自然地,每行复制位置数据,因为存在一对多的关系:一个位置包含多个事件。

清理乘法位置数据的最佳方法是什么?

坚持单个SQL操作,最有意义的是在循环查询结果(行)时执行检查。

但是我似乎无法访问locations对象来检查预先存在的位置ID。

修改 这是SQL输出。如您所见,位置数据自然会多次出现,因为它是跨事件共享的。最终,这将最终以JSON的形式发送,包含嵌套结构,一个用于位置,一个用于事件。

id  title           latlng                  id  title           locationid  
1   Fox Thea...     43.6640673,-79.4213863  1   Bob's Event     1
1   Fox Thea...     43.6640673,-79.4213863  2   Jill's Event    1
2   Wrigley ...     43.6640673,-79.4213863  3   Mary's Event    2
3   Blues Bar       43.6640673,-79.4213863  4   John's Event    3
1   Fox Thea...     43.6640673,-79.4213863  5   Monthly G...    1
1   Fox Thea...     43.6640673,-79.4213863  6   A Special...    1
1   Fox Thea...     43.6640673,-79.4213863  7   The Final...    1

JSON输出。如您所见,位置数据乘以更大的JSON文件。

   {
        "Locations": [
            {
                "ID": 1,
                "Title": "Fox Theatre",
                "Latlng": "43.6640673,-79.4213863",
            },
            {
                "ID": 1,
                "Title": "Fox Theatre",
                "Latlng": "43.6640673,-79.4213863",
            },
            {
                "ID": 2,
                "Title": "Wrigley Field",
                "Latlng": "43.6640673,-79.4213863",
            },
            {
                "ID": 3,
                "Title": "Blues Bar",
                "Latlng": "43.6640673,-79.4213863",
            },
            {
                "ID": 1,
                "Title": "Fox Theatre",
                "Latlng": "43.6640673,-79.4213863",
            },
            {
                "ID": 1,
                "Title": "Fox Theatre",
                "Latlng": "43.6640673,-79.4213863",
            },
            {
                "ID": 1,
                "Title": "Fox Theatre",
                "Latlng": "43.6640673,-79.4213863",
            }
        ],
        "Events": [
            {
                "ID": 1,
                "Title": "Bob's Event",
                "Location": 1
            },
            {
                "ID": 2,
                "Title": "Jill's Event",
                "Location": 1
            },
            {
                "ID": 3,
                "Title": "Mary's Event",
                "Location": 2
            },
            {
                "ID": 4,
                "Title": "John's Event",
                "Location": 3
            },
            {
                "ID": 5,
                "Title": "Monthly Gathering",
                "Location": 1
            },
            {
                "ID": 6,
                "Title": "A Special Event",
                "Location": 1
            },
            {
                "ID": 7,
                "Title": "The Final Contest",
                "Location": 1
            }
        ]

    }

的Structs:

// Event type
type Event struct {
    ID int `schema:"id"`
    Title string `schema:"title"`
    LocationID int `schema:"locationid"`
}

// Location type
type Location struct {
    ID int `schema:"id"`
    Title string `schema:"title"`
    Latlng string `schema:"latlng"`
}

// LocationsEvents type
type LocationsEvents struct {
    Locations []Location `schema:"locations"`
    Events []Event `schema:"events"`
}

运行查询并循环遍历行的函数:

func getLocationsEvents(db *sql.DB, start, count int) ([]Location, []Event, error) {

    var locations = []Location{}
    var events = []Event{}

    rows, err := db.Query("SELECT locations.id, locations.title, locations.latlng, events.id, events.title, events.locationid FROM locations LEFT JOIN events ON locations.id = events.locationid LIMIT ? OFFSET ?", count, start)
    if err != nil {
        return locations, events, err
    }
    defer rows.Close()

    for rows.Next() {
        var location Location
        var event Event

        err := rows.Scan(&location.ID, &location.Title, &location.Latlng, &event.ID, &event.Title, &event.LocationID);
        if err != nil {
                return locations, events, err
        }

    // Here I can print locations and see it getting longer with each loop iteration
    fmt.Println(locations)

    // How can I check if an ID exists in locations?
    // Ideally, if location.ID already exists in locations, then only append event, otherwise, append both the location and event

        locations = append(locations, location)
        events = append(events, event)
    }

    return locations, events, nil
}

路由器调用的函数:

func (a *App) getLocationsEventsJSON(w http.ResponseWriter, r *http.Request) {

count := 99
start := 0

    if count > 10 || count < 1 {
        count = 10
    }
    if start < 0 {
        start = 0
    }

    locations, events, err := getLocationsEvents(a.DB, start, count)
    if err != nil {
        respondWithError(w, http.StatusInternalServerError, err.Error())
        return
    }

    var locationsEvents LocationsEvents

    locationsEvents.Locations = locations
    locationsEvents.Events = events

    respondWithJSON(w, http.StatusOK, locationsEvents)
}

以JSON(REST API的一部分)发送数据的函数:

func respondWithJSON(w http.ResponseWriter, code int, payload interface{}) {
    response, _ := json.Marshal(payload)

    w.Header().Set("Content-Type", "application/json")
    w.WriteHeader(code)
    w.Write(response)
}

更新

恢复使用SQL查询执行此操作,有哪些可能性?使用GROUP BY?这是一个示例SQL:

SELECT locations.id,locations.title,locations.latlng,events.id,events.title,events.locationid 来自地点 LEFT JOIN事件ON locations.id = events.locationid GROUP BY locations.id,events.id

结果集仍然包含重复的位置数据,但它很好地分组和排序。

然后有子查询的可能性: http://www.w3resource.com/sql/subqueries/understanding-sql-subqueries.php但现在我正在运行多个SQL查询,这是我想要避免的。

实际上,我认为在使用像我这样的单一连接查询时,我不能避免重复的位置数据。如果没有复制位置数据,我还会如何收到已连接数据的结果集?让SQL服务器根据需要向我发送预先制作的JSON数据(位置和事件分开)?根据我的理解,收到结果后最好做这项工作。

2 个答案:

答案 0 :(得分:2)

我认为您可以将请求拆分为两个:位置(SELECT * FROM locations)和事件(SELECT * FROM events),然后将它们传递给JSON marshaller。 这两个请求对于数据库来说非常容易和快速。接下来,他们将更容易缓存中间结果。

  

但现在我正在运行多个SQL查询,这是我想避免的。

您能否澄清一下这一刻 - 您为什么要避免多次查询?您想要解决什么任务以及有哪些限制?有时一组小的简单查询比一个过于复杂的查询要好。

答案 1 :(得分:0)

如果您自己查询数据库,则应该首先应该避免重复。 在查询结束时添加&#34; GROUP BY {unique field}&#34;。

应提供事件列表中唯一的位置列表的示例

SELECT location.* 
FROM location.ID, location.Title, location.Latlng
  INNER JOIN event ON event.ID=location.ID
GROUP BY location.ID