次のようなデータを表示する必要がある場合を考えてみましょう。
Parent 1 info
Child 1A info
Child 1B info
...
Parent 2 info
Child 2A info
Child 2B info
...
子は 1 レベルの深さしかないため、データベース レベルで「ネストされたセット」に入る必要がないことに注意してください。たとえば、現在のプロジェクトでは、データを次のように表示する必要があります。
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 についてです。
この場合、最新の売上を記録したアカウントを最初にリストする必要がありますが、もちろん、各アカウントには最大 1 年前までのすべての売上が含まれている必要があります。
最初に、より単純なケースについて質問させてください。たとえば、並べ替え順序は重要ではないとしましょう。次に、アカウント 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
すべての行を取得する場合、問題はありません。単純にクエリを実行し、アプリケーション コード (この場合は PHP) で account_id によって結果にインデックスを付けることができます。
しかし、LIMIT を追加すると、特に古い売上と最近の売上の両方があるアカウントの場合、各アカウントのすべての売上を取得できない可能性があります。
これに対する解決策を思いついたのですが、ここで示している単純化されたバージョンではなく動的クエリ パラメータを扱っているため、かなり複雑です。私の解決策は、2 つの別々のクエリを実行することでした。
まず、必要なすべてのアカウント 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 を $account_ids という PHP 配列に入れ、ページを表示するために必要な実際の結果を返すクエリを作成します。
$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 を implode() 関数のある場所に配置することで、単一のクエリで実現することもできます。たとえば、次のようになります。
WHERE sh.account_id IN (SELECT DISTINCT sh.account_id ... LIMIT 10)
しかし、それはサブクエリの制限とデータベースの移植性に関する懸念を引き起こします.私は異なるデータベースに移植可能な limit() メソッドを使用して制限を設定できるフレームワークを使用していますが、それがどのように反応するかわかりません.たとえば、SQL Serverでこのようなサブクエリで制限を使用しようとしました。
だから、私の本当の質問は、これが問題を解決する最善の方法ですか、それとも別の (より簡単な) 解決策があるのでしょうか? 同様の状況で何をしましたか?