2012-02-14 58 views
7

我一直在考慮這個問題一段時間,它已經到了一個地步,我認爲最好問問周圍,聽聽其他人的想法。準確分頁左加入

我建立了一個存儲Mysql位置的系統。每個位置都有一個類型,一些位置有多個地址。

的表格看起來像這樣

location 
    - location_id (autoincrement) 
    - location_name 
    - location_type_id 

location_types 
    - type_id 
    - type_name (For example "Laundry") 

location_information 
    - location_id (Reference to the location table) 
    - location_address 
    - location_phone 

所以,如果我想查詢數據庫中的10最近添加的我會像這樣的東西去:

SELECT l.location_id, l.location_name, 
     t.type_id, t.type_name, 
     i.location_address, i.location_phone 
FROM location AS l 
LEFT JOIN location_information AS i ON (l.location_id = i.location_id) 
LEFT JOIN location_types AS t ON (l.location_type_id = t.type_id) 
ORDER BY l.location_id DESC 
LIMIT 10 

,對嗎?但問題是,如果一個位置的地址超過1個,那麼限制/分頁不會令人滿意,除非我「GROUP BY l.location_id」,但是這將僅顯示每個地方的一個地址。與有多個地址的地方?

所以我想解決這個是做一個循環內的查詢的唯一途徑..像這樣的東西(僞):

$db->query('SELECT l.location_id, l.location_name, 
      t.type_id, t.type_name 
      FROM location AS l 
      LEFT JOIN location_types AS t ON (l.location_type_id = t.type_id) 
      ORDER BY l.location_id DESC 
      LIMIT 10'); 

$locations = array(); 
while ($row = $db->fetchRow()) 
{ 
    $db->query('SELECT i.location_address, i.location_phone 
       FROM location_information AS i 
       WHERE i.location_id = ?', $row['location_id']); 

    $locationInfo = $db->fetchAll(); 
    $locations[$row['location_id']] = array('location_name' => $row['location_name'], 
              'location_type' => $row['location_type'], 
              'location_info' => $locationInfo); 

} 

現在即時得到的最後10個名額,但這樣做我結束至少10個查詢更多,我不認爲這有助於應用程序的性能。

有沒有更好的方法來實現我在找什麼? (準確的分頁)。

+0

您想要返回某個位置的哪個地址(local_information記錄)?如果你能說出你想要哪一個,我們可以告訴計算機你想要哪一個。 – 2012-02-14 19:29:07

回答

17

這是你的原始查詢

SELECT l.location_id, l.location_name, 
     t.type_id, t.type_name, 
     i.location_address, i.location_phone 
FROM location AS l 
LEFT JOIN location_information AS i ON (l.location_id = i.location_id) 
LEFT JOIN location_types AS t ON (l.location_type_id = t.type_id) 
ORDER BY l.location_id DESC 
LIMIT 10 

你進行最後的分頁。如果你重構這個查詢,你可以更早地執行分頁。

SELECT l.location_id, l.location_name, 
     t.type_id, t.type_name, 
     i.location_address, i.location_phone 
FROM 
    (SELECT location_id,location_type_id FROM location 
    ORDER BY location_id LIMIT 10) AS k 
    LEFT JOIN location AS l ON (k.location_id = l.location_id) 
    LEFT JOIN location_information AS i ON (k.location_id = i.location_id) 
    LEFT JOIN location_types AS t ON (l.location_type_id = t.type_id) 
; 

注意我創建了一個名爲k的子查詢。 10把鑰匙拿起來,並命令首先!

然後JOIN可以從那裏繼續,希望只使用10個location_ids。

會有什麼幫助子查詢k是承載LOCATION_ID和location_type_id

ALTER TABLE location ADD INDEX id_type_ndx (location_id,location_type_id); 

這裏的指數是別的東西,你可能會喜歡這種方法

你如何查詢未來10個IDS(入侵檢測系統11 - 20)?就像這樣:

SELECT l.location_id, l.location_name, 
     t.type_id, t.type_name, 
     i.location_address, i.location_phone 
FROM 
    (SELECT location_id,location_type_id FROM location 
    ORDER BY location_id LIMIT 10,10) AS k 
    LEFT JOIN location AS l ON (k.location_id = l.location_id) 
    LEFT JOIN location_information AS i ON (k.location_id = i.location_id) 
    LEFT JOIN location_types AS t ON (l.location_type_id = t.type_id) 
; 

所有你需要做的是改變子查詢kLIMIT條款與每個新頁面。

  • LIMIT 20,10
  • LIMIT 30,10
  • 等等...

我可以通過刪除位置表提高了重構,並有子查詢ķ攜帶所需的字段是這樣的:

SELECT k.location_id, k.location_name, 
     t.type_id, t.type_name, 
     i.location_address, i.location_phone 
FROM 
    (SELECT location_id,location_type_id,location_name 
    FROM location ORDER BY location_id LIMIT 10,10) AS k 
    LEFT JOIN location_information AS i ON (k.location_id = i.location_id) 
    LEFT JOIN location_types AS t ON (k.location_type_id = t.type_id) 
; 

製作,對於這個版本的額外指標就沒有必要。

試試吧!

+0

鑑於使用增加的LIMIT在多頁之後可能很昂貴,主要想法是好的。 – Alfabravo 2012-02-14 19:55:59

+0

謝謝!這是我正在尋找的那種查詢,從來沒有想過要做這樣的子查詢! – mpratt 2012-02-14 20:03:19

2

有解決這幾個方面:

  • 你可以一個IsPrimary位列添加到location_information表,並添加一個觸發器,以保證每個位置始終只有一個location_information記錄與此設置爲1
  • 如果您沒有DateCreatedDateModified列,您可以使用location_id列來選擇最早或最新的location_information記錄(MIN/MAX)。
3
比循環和10次的查詢更好

,可以查詢該location.location_id極限10分頁,即串聯成一個逗號分隔字符串,然後全面查詢來獲取WHERE location.location_id IN (1,2,3...{list of ids})

3

你可以與去你最初的想法是根據location_id進行分組,然後使用group_concat函數將該位置的所有地址顯示爲1字段。

SELECT l.location_id, l.location_name, 
    t.type_id, t.type_name, 
    group_concat(concat("Address: ",i.location_address, " Phone: ", i.location_phone)) as addresses 
FROM location AS l 
LEFT JOIN location_information AS i ON (l.location_id = i.location_id) 
LEFT JOIN location_types AS t ON (l.location_type_id = t.type_id) 
GROUP BY l.location_id 
ORDER BY l.location_id DESC 
LIMIT 10