2017-07-02 68 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查詢,這是我想避免的。

你能否澄清這一刻 - 爲什麼你想避免多個查詢?你想要解決什麼任務和有什麼限制?有時候,一些小的簡單查詢比一個過於複雜的查詢更好。