2012-07-30 98 views
3

我有三個表:friendslocationsfriend_locationSQL查詢一個多一對多的關係

friend_location是一個連接表,讓friendslocations之間的許多一對多的關係,所以表將是這個樣子:

朋友


ID | Name 
1 | Jerry 
2 | Nelson 
3 | Paul 

位置


ID | Date  | Lat | Lon 
1 | 2012-03-01 | 34.3 | 67.3 
2 | 2011-04-03 | 45.3 | 49.3 
3 | 2012-05-03 | 32.2 | 107.2 

friend_location


Friend_ID | Location_id 
1   | 2 
2   | 1 
3   | 3 
2   | 2 

我想這樣做的就是讓每個朋友的最新位置。

結果


ID | Friend | Last Know Location | last know date 
1 | Jerry | 45.3 , 49.3  | 2011-04-03 
2 | Nelson | 34.3 , 67.3  | 2012-03-01 
3 | Paul | 32.2 , 107.2  | 2012-05-03 

這是在尋找各種實例之後我都試過了,但它返回了許多成果,是不正確的:


    select f.id , f.name , last_known_date 
    from friends f, (

    select distinct fl.friend_id as friend_id, fl.location_id as location_id, m.date as last_known_date 
    from friend_location fl 

    inner join (
     select location.id as id, max(date) as date 
     from location 
     group by location.id 
    ) m 

    on fl.location_id=m.id 

    ) as y 
    where f.id=y.friend_id 

任何建議,將不勝感激。

+0

請列出您正在使用的數據庫的類型...這很大程度上影響了答案,因爲窗口函數使事情變得簡單和簡潔(但在所有數據庫中都不可用)。 – 2012-07-30 03:29:15

+0

您可能需要考慮將最後一個已知日期轉換爲單獨的表格 – cordialgerm 2012-07-30 04:51:39

+0

使用PostgrisSQL。謝謝。 – Cysneros 2012-07-30 06:01:11

回答

1

你可以做這樣的事情:

SELECT f.id, f.name, last_known_date, l.Lat, L.Lon 
from Friends f 
join 
(
    select f.id, MAX(l.Date) as last_known_date 
    from Friends f 
    JOIN Friend_Location fl on f.ID = fl.Friend_ID 
    JOIN Location l on l.ID = fl.Location_ID 
    GROUP BY f.id 
) FLMax 
on FLMax.id = f.id 
join Friend_Location fl on fl.friend_ID = f.ID 
join Location l on fl.location_ID = l.ID AND l.Date = FLMax.Last_Known_Date 

基本上你的問題是,你是通過location.id這將給你所有的位置,因爲ID是唯一的分組。

這隻適用於朋友只能在任何一個時間在1個位置。

+0

通過將日期放入Friend_Location表格中,您可能可以更好地規範表格。使用您當前的設計,朋友多次登錄同一地點將創建多個地點記錄。 – Greg 2012-07-30 03:05:24

+0

非常感謝大家!他們都很棒。我唯一添加的是一個DISTINCT,以確保每次輸入只返回一個結果。 – Cysneros 2012-08-02 22:11:22

0

您的數據佈局有點奇怪,因爲日期位於位置表中。所以,下面的檢索每個朋友的最新日期:

select fl.friend_id, max(l.date) as maxdate 
from friend_location fl 
    location l join 
    on fl.location_id = l.location_id 

現在,就讓我們一起回來的信息,這個查詢:

select f.*, maxdate, l.* 
from (select fl.friend_id, max(l.date) as maxdate 
     from friend_location fl 
     JOIN location l 
      on fl.location_id = l.id 
     group by fl.friend_id 
    ) flmax join 
    friends f 
     on flmax.friend_id = f.id 
    join location l 
     on l.date = flmax.maxdate 

這將工作,假設位置不有重複的日期。如果他們這樣做,查詢會有點複雜。我們可以做出這個假設嗎?

0

您可以使用:

SELECT 
    a.*, 
    CONCAT(d.Lat, ' , ', d.Lon) AS last_known_location, 
    d.Date AS last_known_date 
FROM 
    friends a 
JOIN 
(
    SELECT a.Friend_ID, MAX(b.Date) AS maxdate 
    FROM  friend_location a 
    JOIN  location b ON a.Location_id = b.ID 
    GROUP BY a.Friend_ID 
) b ON a.ID = b.Friend_ID 
JOIN 
    friend_location c ON b.Friend_ID = c.Friend_ID 
JOIN 
    location d ON c.Location_id = d.ID AND b.maxdate = d.Date 
1

Gregs查詢看起來正確的給我,我想出了一個類似(見下文)。然而,當兩個朋友以不同的順序訪問相同的位置時,當前的數據庫模式不處理情況對我而言,Date列應該位於friend_location表中,而不是位置。但是,如果不是那麼查詢是:

SELECT F.ID, F.Name AS Friend, L.Lat, L.Lon, L.Date 
FROM 
(
    SELECT MAX(L.date) AS max_date, F.ID 
    FROM Friends F 
    JOIN friend_location FL ON F.ID=FL.Friend_ID 
    JOIN Location L ON L.ID=FL.Location_id 
    GROUP BY F.ID 
) AS X 
JOIN Friends F ON X.ID=F.ID 
JOIN friend_location FL ON F.ID=FL.Friend_ID 
JOIN location L ON L.ID=FL.Location_id AND L.Date=X.max_date