2011-12-13 93 views
0

最新條目我有3個表SQL:從歷史表

person (id, name) 
area (id, number) 
history (id, person_id, area_id, type, datetime) 

在這個表我保存它的人在特定的時間有這方面的信息。這就像一個推銷員在一個地區旅行一段時間,然後他得到另一個區域。他一次也可以有多個區域。

歷史記錄類型='我'爲CheckIn或'O'爲結帳。 例子:

id person_id area_id type datetime 
1  2   5   'O'  '2011-12-01' 
2  2   5   'I'  '2011-12-31' 
A person started traveling in area 5 at 2011-12-01 and gave it back on 2011-12-31. 

現在我想將所有區域的所有人員必須馬上列表。

person1.name, area1.number, area2.number, area6.name 
person2.name, area5.number, area9.number 
.... 

輸出也能像這樣太(沒關係):

person1.name, area1.number 
person1.name, area2.number 
person1.name, area6.number 
person2.name, area5.number 
.... 

我怎麼能這樣做?

+0

所以,你正在尋找一個目前有一個地區檢查出來的人,但還沒有檢查過它的列表? – ean5533 2011-12-13 20:52:37

+0

我個人建議不要將`type`存儲爲`char`值(或者至少在它的寂寞中) - 將它作爲fk引用存儲到一張表中,詳細說明這個值_means_(像你的`person`和`區域表格)。這將條目限制爲有效值,可以隨時更新(很容易),而不需要「alter」語句......等等。 – 2011-12-13 21:50:34

回答

1

這個問題,的確,相當棘手。您需要歷史記錄中的條目列表,其中對於給定用戶和區域,存在沒有後續「我」記錄的「O」記錄。只用歷史表工作,這相當於:

SELECT ho.person_id, ho.area_id, ho.type, MAX(ho.datetime) 
    FROM History AS ho 
WHERE ho.type = 'O' 
    AND NOT EXISTS(SELECT * 
        FROM History AS hi 
        WHERE hi.person_id = ho.person_id 
        AND hi.area_id = ho.area_id 
        AND hi.type = 'I' 
        AND hi.datetime > ho.datetime 
       ) 
GROUP BY ho.person_id, ho.area_id, ho.type; 

然後,因爲你只有這個人的名字和該地區的號碼後是真的(儘管爲什麼區域號碼不能是同它的ID我我不知道),你需要稍微適應,與額外的兩個表加入:

SELECT p.name, a.number 
    FROM History AS ho 
    JOIN Person AS p ON ho.person_id = p.id 
    JOIN Area AS a ON ho.area_id = a.id 
WHERE ho.type = 'O' 
    AND NOT EXISTS(SELECT * 
        FROM History AS hi 
        WHERE hi.person_id = ho.person_id 
        AND hi.area_id = ho.area_id 
        AND hi.type = 'I' 
        AND hi.datetime > ho.datetime 
       ); 

的NOT EXISTS子句是一個相關子查詢;這往往是低效的。你也許可以重鑄它作爲一個LEFT OUTER適當的加入和過濾條件JOIN:

SELECT p.name, a.number 
    FROM History AS ho 
    JOIN Person AS p ON ho.person_id = p.id 
    JOIN Area AS a ON ho.area_id = a.id 
    LEFT OUTER JOIN History AS hi 
    ON hi.person_id = ho.person_id 
    AND hi.area_id = ho.area_id 
    AND hi.type = 'I' 
    AND hi.datetime > ho.datetime 
WHERE ho.type = 'O' 
    AND hi.person_id IS NULL; 

所有SQL未經驗證。

0

您正在查找每行可能有不同列數的結果嗎?我想你可能想看看GROUP_CONCAT()

SELECT p.`id`, GROUP_CONCAT(a.`number`, ',') AS `areas` FROM `person` a LEFT JOIN `history` h ON h.`person_id` = p.`id` LEFT JOIN `area` a ON a.`id` = h.`area_id` 

我沒有測試此查詢,但我已經在類似的方式之前使用組CONCAT。當然,你會想要適應你的需要。當然,組concat會返回一個字符串,所以需要後處理才能使用這些數據。

編輯我thikn你的問題已經編輯,因爲我開始迴應。我的查詢並不真正適合你的要求了......

0

試試這個:

select * 
from person p 
inner join history h on h.person_id = p.id 
left outer join history h2 on h2.person_id = p.id and h2.area_id = h.area_id and h2.type = 'O' 
inner join areas on a.id = h.area_id 
where h2.person_id is null and h.type = 'I'