0

少し検索して読んだ後、アプリケーション用に次の SQL クエリを思いつきました。

SELECT
  ROUND(AVG(CASE WHEN gender = 'M' THEN rating END), 1) avgAllM,
  COUNT(CASE WHEN gender = 'M' THEN rating END) countAllM,
  ROUND(AVG(CASE WHEN gender = 'F' THEN rating END), 1) avgAllF,
  COUNT(CASE WHEN gender = 'F' THEN rating END) countAllF,
  ROUND(AVG(CASE WHEN gender = 'M' AND UserAge(birth_date) <= 18 THEN rating END), 1) avgU18M,
  COUNT(CASE WHEN gender = 'M' AND UserAge(birth_date) <= 18 THEN rating END) countU18M,
  ROUND(AVG(CASE WHEN gender = 'F' AND UserAge(birth_date) <= 18 THEN rating END), 1) avgU18F,
  COUNT(CASE WHEN gender = 'F' AND UserAge(birth_date) <= 18 THEN rating END) countU18F
FROM movie_ratings mr INNER JOIN accounts a
  ON mr.aid = a.aid
WHERE mid = 5;

そして、可能であれば、これをどのように単純化できるか疑問に思っています。birth_dateフィールドは型DATEであり、そのUserAge日付フィールドから年齢を計算する関数です。

テーブル構造は次のとおりです。

[ACCOUNTS]
aid(PK), birth_date, gender

[MOVIE_RATINGS]
mid(PK), aid(PK,FK), rating

私は2つのことを探しています:

  • 経験豊富なユーザーが知っていて、私が知らない上記のコードの一般的な単純化。
  • 私はこれを PHP で行っており、レコードごとに、これらすべての変数を含む連想配列を作成します。それらを多次元配列にグループ化する方法を探しているので、PHP コードが読みやすくなります。もちろん、PHP 自体でこれを実行したくはありません。無意味です。

たとえば、次のようなものです。

$info[0]['avgAllM']
$info[0]['countAllM']
$info[1]['avgAllF']
$info[1]['countAllF']
$info[2]['avgU18M']
$info[2]['countU18M']
$info[3]['avgU18F']
$info[3]['countU18F']

それ以外の:

$info['avgAllM']
$info['countAllM']
$info['avgAllF']
$info['countAllF']
$info['avgU18M']
$info['countU18M']
$info['avgU18F']
$info['countU18F']

これが可能かどうかさえわからないので、それが可能かどうか、そしてどのように可能かについて本当に疑問に思っています。

なぜ私はこれをすべてしたいのですか?上記の SQL クエリは、実行する必要がある完全な SQL の一部にすぎません。すべての作業を行う前に、同じ結果を達成するためのよりコンパクトな SQL クエリがあるかどうかを知りたいので、まだ行っていません。基本的に、上記のような行をいくつか追加しますが、特に日付については条件が異なります。

4

2 に答える 2

3

VIEW次の定義でを作成できます

SELECT
      CASE WHEN gender = 'M' THEN rating END AS AllM,
      CASE WHEN gender = 'F' THEN rating END AS AllF,
      CASE WHEN gender = 'M' AND UserAge(birth_date) <= 18 THEN rating END AS U18M,
      CASE WHEN gender = 'F' AND UserAge(birth_date) <= 18 THEN rating END AS U18F
      FROM movie_ratings mr INNER JOIN accounts a
        ON mr.aid = a.aid
      WHERE mid = 5

次に、そこから選択します

SELECT ROUND(AVG(AllM), 1) avgAllM,
       COUNT(AllM)         countAllM,
       ROUND(AVG(AllF), 1) avg,
       COUNT(AllF)         countAllF,
       ROUND(AVG(U18M), 1) avgU18M,
       COUNT(U18M)         countU18M,
       ROUND(AVG(U18F), 1) avgU18F,
       COUNT(U18F)         countU18F
FROM  yourview

物事を少し単純化するかもしれませんか?

于 2011-01-05T01:44:16.083 に答える
0

これは、最適化が早すぎる場合にすぎない可能性があります。クエリは必要なことを実行しますが、複雑に見えるだけです。必ずしも役立つトリックがあるかどうかはわかりません。おそらく、データの特性に依存します。クエリは遅いですか?もっと速くできると思いますか?

次のように再配置する価値があるかもしれません。すべての条件はテーブルに依存しているため、ACCOUNTSテーブルよりも大幅に小さくなると想定しているためMOVIE_RATINGS、より小さなデータセットですべての計算を実行できる可能性があり、より高速になる可能性があります。ただし、一度に 1 つのムービーのみを選択する場合 ( mid = 5) は、おそらくそうではありません。

これが機能するかどうかは完全にはわかりませんが、そうすべきだと思います。

SELECT
  ROUND(AVG(rating * AllM), 1) avgAllM,
  COUNT(rating * AllM) countAllM,
  ROUND(AVG(rating * AllF), 1) avgAllF,
  COUNT(rating * AllF) countAllF,
  ROUND(AVG(rating * AllM * U18), 1) avgU18M,
  COUNT(rating * AllM * U18) countU18M,
  ROUND(AVG(rating * AllM * U18), 1) avgU18F,
  COUNT(rating * AllM * U18) countU18F
FROM 
  movie_ratings mr 
  INNER JOIN (
    select 
      aid,
      case when gender = 'M' then 1 end as AllM,
      case when gender = 'F' then 1 end as AllF,
      case when UserAge(birth_date) <= 18 then 1 end as U18
    from accounts) a ON mr.aid = a.aid
WHERE mid = 5;

ただし、バランスをとって、おそらくあなたが持っているクエリをそのままにしておくでしょう。あなたが持っているクエリは理解しやすく、おそらくかなりうまく機能します。

于 2011-01-05T12:58:28.130 に答える