1

次のようなデータを表示する必要がある場合を考えてみましょう。

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でこのようなサブクエリで制限を使用しようとしました。

だから、私の本当の質問は、これが問題を解決する最善の方法ですか、それとも別の (より簡単な) 解決策があるのでしょうか? 同様の状況で何をしましたか?

4

1 に答える 1

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

データベースに依存しないようにしようとしましたが、句を SQL Serverlimitに変換する必要があります。select top 10

于 2013-01-09T17:25:29.110 に答える