3

特に、次の2つのテーブルを含むデータベースがあります。

classesは、クラススケジュールのクラスごとに1つの行を持つ単純なテーブルです。

sessionsは、各クラスが出会う日時を特徴付けるテーブルであり、各行は次のような概念を表現できます。

"火曜日|1月22日-3月5日|6-9pm"
"火曜日と木曜日|1月22日-3月7日|6-9pm"
"月曜日-木曜日|1月21-24日|3-6pm"
"土曜日|3月9日|9am-午後4時"

等々。

sessionsの各行には少なくとも1つの行が存在することが保証されてclassesおり、特定のクラスでは、2つ以上の関連するセッション行が存在する場合があります。

現在、次のように、2つの異なるクエリを使用して、特定の基準セットに一致するクラスのクラスおよびセッション情報を取得しています。

select c.class_id, c.title, c.instructor, c.num_seats, c.price
  from classes c
  join classes_by_department cbd 
    on (cbd.class_id = c.class_id)
  join /* several other tables */
    on /* several other join conditions */
 where cbd.department_id = '{$dept_id}'
   and /* several other qualifying conditions */
;

この:

select s.class_id, s.start_date, s.end_date, s.day_bits, s.start_time, s.end_time
  from sessions s
  join classes c
    on (c.class_id = s.class_id)
  join classes_by_department cbd
    on (cbd.class_id = s.class_id) 
  join /* the same other tables */
    on /* the same other join conditions */
 where cbd.department_id = '{$dept_id}'
   and /* the same other qualifying conditions */
;

これは正常に機能し、少なくとも現在のアプリケーションでは、テーブルが十分に大きくなく、トラフィックが十分に多くないため、2つのクエリが問題になります。それにもかかわらず、それは少し無駄だと思います。最初のクエリですでに行われた作業を活用して、2番目のクエリを実行する方法がないのではないかと思います(同じクエリを2回実行することになります。別の列を選択するだけです)。

もちろん、1つのクエリ(2番目のクエリ)から関連するすべての列を選択できることはわかっていますclassessessions、現在のアプローチでは、最初のクエリが、修飾クラスごとに1行だけを配信するという事実が気に入っています。クラスにはセッションレコードがあるため、多くの行。クエリをマージした場合、クエリ結果を処理する既存のロジックを再構築する必要があります。(ええ、私は知っています、waah ...)

私が思いついた解決策の1つは、最初のクエリによって返されたすべてのをベクトルに収集しclass_id(とにかくそれらの結果を反復処理する必要があるため)、そのベクトルの内容を句の値リストの内容としてフォーマットすることです。 IN、2番目のクエリが単純に次のようになるようにします。

select s.class_id, s.start_date, s.end_date, s.day_bits, s.start_time, s.end_time
  from sessions s
 where s.class_id in (/* value-list */);

巨大なSQLクエリは大したことではないことを理解しているので、このようなソリューションのスケーラビリティについてはあまり心配していません。さらに、で定義されたインデックスを利用できますsessions.class_id

しかし...まあ...SQLチョップを改善しようとしている人にとってはあまり満足のいくものではありません。これはかなり初歩的なことです。それはエレガントではなく、あまり「SQLっぽい」ものではなく、Pythonicという用語に相当するSQLが何であれ、そうではありません。

誰かがもっと適切なことを提案できますか?

4

2 に答える 2

1

あなたが望むことを行う標準的な方法は、ビューを使用することです。最初のクエリを次のように定義します。

create view vw_MyClasses as
    select c.class_id, c.title, c.instructor, c.num_seats, c.price, cbd.department_id
    from classes c
         join classes_by_department cbd 
         on (cbd.class_id = c.class_id)
         join /* several other tables */
         on /* several other join conditions */
   where /* several other qualifying conditions */

次に、クラスクエリは次のようになります。

select *
from vw_MyClasses
where department_id = '{$dept_id}'

次に、2 番目のクエリは次のようになります。

 select s.class_id, s.start_date, s.end_date, s.day_bits, s.start_time, s.end_time
 from sessions s
 where s.class_id in (select class_id from vw_MyClasses 
                                      where department_id = '{$dept_id}');

または、MySQL でより効率的なものは次のとおりです。

 select s.class_id, s.start_date, s.end_date, s.day_bits, s.start_time, s.end_time
 from sessions s
 where exists (select 1 from vw_MyClasses mc where mc.class_id = s.class_id limit 1)

これには十分な理由があります。このようなロジックを複数のクエリで繰り返すことは、メンテナンスの悪夢になります。ロジックを 1 か所で変更すると、すべての場所を変更するのを忘れがちです。ビューだけでは不十分な場合があるため、ここで説明されているように、ユーザー定義関数を使用する必要がある場合があります。

また、基準が非常に有用な場合は、それらを識別するためにクラス テーブルにフラグを設定することもできます。これには、夜間の更新やトリガーの使用など、何らかの方法でそれらを維持する必要があります。

于 2012-12-28T15:11:08.440 に答える
0

正直なところ、私は気にしません。まず、あなたが私たちに言ったことから、それはうまく機能し、私にはかなりエレガントに見えます. 次に、2 番目のクエリで余分なデータを戻す理由がない場合は、そうしないでください。第三に、そして最も重要なことは、現状では、何が起こっているのかを理解するのはかなり簡単だということです。これを解読しようとしているのが常にあなただけであるとは限らず、他の人がコードを読み取れることが重要です。複雑すぎる SQL クエリは良くありません。

そのままでいいと思いますし、SQLっぽさもいいです。

于 2012-12-28T08:17:26.147 に答える