2017-07-02 58 views
0

我正在为位置和事件(发生在位置)运行联合SQL查询。在结果中,由于存在一对多关系,所以位置数据自然会在每行进行复制:一个位置包含多个事件。前往:删除SQL连接结果后的重复行

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

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

但是我似乎无法访问位置对象来检查预先存在的位置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) 
} 

UPDATE:

恢复到与SQL查询这样做,有哪些可能性?使用GROUP BY?下面是一个例子SQL:

SELECT locations.id,locations.title,locations.latlng,events.id,events.title,events.locationid FROM位置 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数据发送给我(位置和事件分离)?根据我的理解,在收到结果后最好做这件事。

+0

提供一个数据示例,您可以在此刻收到数据以及预期结果。从你提供的代码中的查询来看,你并不清楚你观察到了什么样的重复:只有当你的原始数据包含重复数据时,唯一的方法就是获得这些重复数据。 – zerkms

+0

使用SQL行输出编辑OP。 – MarsAndBack

+0

我在那里看不到重复的行:每行都是您刚发布的值的唯一组合。 – zerkms

回答

0

如果你自己查询数据库,你应该能够避免任何重复。 在查询结尾添加“GROUP BY {unique field}”。

例,应该给的是你的事件列表中的位置的唯一列表

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

嗨我试过这种方法,但不成功。对特定字段使用GROUP BY最终会消除行。在GROUP BY中使用多个字段有助于按组排序行。请参阅OP编辑。 – MarsAndBack

+0

啊,我这次更详细地研究了你的餐桌结构。你在位置和事件之间建立了多对多的连接。活动是否可以在多个地点举行?或者它只是可以用于许多事件的相同位置? – Skov

+0

可以用于许多活动的相同位置。 – MarsAndBack

1

我认为你可以分成两部分,你的要求:位置(SELECT * FROM locations)和事件(SELECT * FROM events),然后将它们传递给JSON编组。 这2个请求对于数据库执行将非常简单快捷。接下来他们将更容易缓存中间结果。

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

你能否澄清这一刻 - 为什么你想避免多个查询?你想要解决什么任务和有什么限制?有时候,一些小的简单查询比一个过于复杂的查询更好。