7

これが私のスキーマと問題の基本的な内臓です:http ://sqlfiddle.com/#!1/72ec9/4/2

期間テーブルは可変範囲の時間を参照できることに注意してください。シーズン全体の場合もあれば、数ゲームまたは1ゲームの場合もあります。特定のチームと年について、すべての期間の行は排他的な時間範囲を表します。

テーブルを結合し、GROUP BYのperiods.yearを使用してシーズンのスコアを集計するクエリを作成しました(sqlfiddleを参照)。ただし、コーチが同じ年に2つのポジションを持っていた場合、GROUPBYは同じ期間の行を2回カウントします。コーチが2つのポジションを保持しているが、1年が複数の期間で構成されている場合でも期間を合計する場合、どうすれば重複を破棄できますか?スキーマを作成するためのより良い方法があれば、私に指摘していただければ幸いです。

4

3 に答える 3

10

根本的な問題(複数の一致を持つ複数のテーブルへの結合)は、この関連する回答で説明されています。

修正するために、最初にクエリを簡略化してフォーマットしました。

select pe.year
     , sum(pe.wins)       AS wins
     , sum(pe.losses)     AS losses
     , sum(pe.ties)       AS ties
     , array_agg(po.id)   AS position_id
     , array_agg(po.name) AS position_names
from   periods_positions_coaches_linking pp
join   positions po ON po.id = pp.position
join   periods   pe ON pe.id = pp.period
where  pp.coach = 1
group  by pe.year
order  by pe.year;

元の結果と同じ誤った結果が得られますが、よりシンプル/高速/読みやすくなります。

  • リストcoach内の列を使用しない限り、テーブルを結合しても意味がありません。完全に削除し、状態をSELECTに置き換えました。WHEREwhere pp.coach = 1

  • 必要ありませんCOALESCENULL集計関数では値は無視されますsum()。代用する必要はありません0

  • テーブルエイリアスを使用して、読みやすくします。

次に、私はあなたの問題を次のように解決しました:

SELECT *
FROM  (
   SELECT pe.year
        , array_agg(DISTINCT po.id)   AS position_id
        , array_agg(DISTINCT po.name) AS position_names
   FROM   periods_positions_coaches_linking pp
   JOIN   positions                         po ON po.id = pp.position
   JOIN   periods                           pe ON pe.id = pp.period
   WHERE  pp.coach = 1
   GROUP  BY pe.year
   ) po
LEFT   JOIN (
   SELECT pe.year
        , sum(pe.wins)   AS wins
        , sum(pe.losses) AS losses
        , sum(pe.ties)   AS ties
   FROM  (
      SELECT period
      FROM   periods_positions_coaches_linking
      WHERE  coach = 1
      GROUP  BY period
      ) pp
   JOIN   periods pe ON pe.id = pp.period
   GROUP  BY pe.year
   ) pe USING (year)
ORDER  BY year;
  • それらに参加する前に、ポジションと期間を別々に集約します。

  • 最初のサブクエリ poリストでは、。を使用して1回だけ配置しますarray_agg(DISTINCT ...)

  • 2番目のサブクエリでpe...

    • GROUP BY period、コーチは期間ごとに複数のポジションを持つことができるためです。
    • JOIN期間へ-その後のデータそして合計を取得するために集計します。

db <> fiddle here
Old sqlfiddle

于 2012-10-03T19:19:17.137 に答える
2

ここdistinctに示すように使用します

コード:

select periods.year as year,
sum(coalesce(periods.wins, 0)) as wins,
sum(coalesce(periods.losses, 0)) as losses,
sum(coalesce(periods.ties, 0)) as ties,
array_agg( distinct positions.id) as position_id,
array_agg( distinct positions.name) as position_names

from periods_positions_coaches_linking

join coaches on coaches.id = periods_positions_coaches_linking.coach
join positions on positions.id = periods_positions_coaches_linking.position
join periods on periods.id = periods_positions_coaches_linking.period

where coaches.id = 1

group by periods.year, positions.id
order by periods.year;
于 2012-10-03T19:21:31.257 に答える
2

あなたの場合、最も簡単な方法は、ポジションを分割することかもしれません:

select periods.year as year,
       sum(coalesce(periods.wins, 0))/COUNT(distinct positions.id) as wins,
       sum(coalesce(periods.losses, 0))/COUNT(distinct positions.id) as losses,
       sum(coalesce(periods.ties, 0))/COUNT(distinct positions.id) as ties,
       array_agg(distinct positions.id) as position_id,
       array_agg(distinct positions.name) as position_names
from periods_positions_coaches_linking join
     coaches
     on coaches.id = periods_positions_coaches_linking.coach join
     positions
     on positions.id = periods_positions_coaches_linking.position join
     periods
     on periods.id = periods_positions_coaches_linking.period
where coaches.id = 1
group by periods.year
order by periods.year;

ポジションの数は勝ち、負け、引き分けをスケーリングするので、それを分割するとカウントが調整されます。

于 2012-10-03T19:23:48.490 に答える