2013-01-09 39 views
1

考慮這樣的情況,你需要這樣的顯示數據保持嵌套行在一起:動態ORDER BY和LIMIT /分頁

Parent 1 info 
    Child 1A info 
    Child 1B info 
    ... 
Parent 2 info 
    Child 2A info 
    Child 2B info 
    ... 

注意,孩子們只去一個層次深,所以沒有必要弄轉換爲數據庫級的「嵌套集」。舉例來說,在我的當前項目,數據需要顯示這樣的:

First name | Last name | City | ... 
--------------------------------- 
John  | Doe  | Denver 

    Sales: 
    --------------------- 
    Date | Total | ... 
    ----------------- 
    Jan 1 | $100 
    Jan 15 | $200 
    Feb 1 | $100 

Suzie  | Springer | New York 

    Sales: 
    --------------------- 
    Date | Total | ... 
    ----------------- 
    ... 

我的問題是關於獲取數據這一頁,同時還通過使用LIMIT子句做分頁所需的SQL(或等值)。

在這種情況下,最近銷售的帳戶應該首先列出,但當然每個帳戶都需要在一年前擁有其所有的銷售額。

讓我先問一個更簡單的例子:假設排序順序沒有關係。然後,我可以簡單地通過帳戶ID(簡化的示例)命令:

SELECT sh.account_id, a.first_name, a.last_name, 
    sh.sale_id, sh.total, sh.payment_time 
FROM sales_header sh 
JOIN account a on sh.account_id = a.account_id 
WHERE a.account_type = 'parent' 
ORDER BY sh.account_id 

但引入分頁時,人們怎麼會確保所有特定帳戶的銷售都放在一起?很難知道LIMIT應該有多大。

現在,讓我們添加更多有需要的真正的排序順序:

SELECT sh.account_id, a.first_name, a.last_name, 
    sh.sale_id, sh.total, sh.payment_time 
FROM sales_header sh 
JOIN account a on sh.account_id = a.account_id 
WHERE a.account_type = 'parent' 
ORDER BY sh.payment_time 

當檢索所有行,沒有任何問題 - 我可以簡單地運行查詢,然後指數在我的應用程序代碼的結果通過ACCOUNT_ID(PHP在這種情況下)。

但是,如果我添加一個LIMIT,那麼我可能無法獲得每個帳戶的所有銷售額,尤其是對於既有舊銷售又有近期銷售的帳戶。

我想出了一個解決方案,但它很複雜,特別是因爲我正在處理動態查詢參數而不是我在這裏展示的簡化版本。我的解決方案是運行兩個單獨的查詢。

首先,獲得我需要的所有帳戶ID:

SELECT DISTINCT sh.account_id 
FROM sales_header sh 
JOIN account a on sh.account_id = a.account_id 
WHERE a.account_type = 'parent' 
ORDER BY sh.payment_time 
LIMIT 10 

然後,把ID添加到PHP數組名爲$ account_ids,然後構建返回來顯示頁面所需的實際結果查詢:

$sql = 'SELECT sh.account_id, a.first_name, a.last_name, 
    sh.sale_id, sh.total, sh.payment_time 
FROM sales_header sh 
JOIN account a on sh.account_id = a.account_id 
WHERE sh.account_id IN ('. implode(',', $account_ids). ') 
ORDER BY sh.payment_time'; 

當然,這也可以在一個查詢中通過將其中的破滅()函數是 第一次查詢的SQL,喜歡的東西來完成

WHERE sh.account_id IN (SELECT DISTINCT sh.account_id ... LIMIT 10) 

但是,這引起了人們對在子查詢和數據庫可移植性的限制的擔憂 - 我使用了一個框架,可以讓你使用的限制()方法,它是便攜式 到不同的數據庫設置的限制,但我例如,如果我試圖在SQL Server這樣的子查詢 中使用限制,不知道它會如何反應。

所以,我真正的問題是:這是解決問題的最好方法,還是有一個替代(更簡單)的解決方案?你在類似的情況下做了什麼?

+0

同樣感興趣的,特別是如果你使用SQL Server: http://stackoverflow.com/questions/10187066/how-do-i-remove-duplicates-in-paging –

回答

1
SELECT 
    sh.account_id, a.first_name, a.last_name, 
    sh.sale_id, sh.total, sh.payment_time 
FROM 
    sales_header sh 
    inner JOIN 
    account a on sh.account_id = a.account_id 
    inner join (
     SELECT sh.account_id, max(sh.payment_time) payment_time 
     FROM 
      sales_header sh 
      inner JOIN 
      account a on sh.account_id = a.account_id 
     WHERE a.account_type = 'parent' 
     group by sh.account_id 
     order by 2 desc 
     limit 10 
    ) acs on acs.account_id = a.account_id 
ORDER BY acs.payment_time desc, acs.account_id, sh.payment_time desc 

我試圖使它DB不可知,但limit子句必須在SQL Server中轉換爲select top 10

+0

@馬特編輯查詢。 –

+0

感謝您的回答。 '2 by order'是否是一個錯字?如果不是,它的目的是什麼? 'acs'應該是subuery的別名(看起來像子查詢也缺少'on'語句)? –

+0

好的,我想通過SELECT語句中的第二個字段來命令...'order by 2'意味着...在這種情況下,max(sh.payment_time)'。很酷,我不知道你能做到這一點。 –