2

私はこのテーブルを持っています:

CREATE TABLE schedule (
schedule_id serial NOT NULL,
start_date date,
CONSTRAINT schedule_id PRIMARY KEY (schedule_element_id)
)

そして、このテーブル:

CREATE TABLE schedule_user (
schedule_user_id serial NOT NULL,
schedule_id integer,
state int,
CONSTRAINT fk_schedule_id   FOREIGN KEY (schedule_id)
      REFERENCES schedule (schedule_id) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION
)
スケジュール
 -------------------------
|スケジュール_id |日付 |
|------------+------------|
|1 |'2013-10-10'|
|2 |'2013-10-20'|
|3 |'2013-08-13'|
 -------------------------

スケジュール_ユーザー
 -----------------------------------
|スケジュール_ユーザー_id|スケジュール_id |状態|
|----------------+------------+-----|
|1 | 1 |0 |
|2 | 1 |1 |
|3 | 1 |2 |
|4 | 1 |0 |
|5 | 1 |1 |
|6 | 1 |1 |
|4 | 2 |0 |
|5 | 2 |1 |
|7 | 2 |0 |
|2 | 3 |1 |
 -----------------------------------

そして、次のようなテーブルが必要です。

特性
 ------------------------------------------------------
|スケジュール_id |状態0|状態1|状態2|合計|
|------------+------+------+------+-----|
|1 |2 |3 |1 |6 |
|2 |2 |1 |0 |3 |
|3 |1 |1 |0 |2 |
 ------------------------------------------------------

パフォーマンスと同じくらいひどいクエリを作成しました。

SELECT 
    schedule.schedule_id AS id, 
    (( SELECT count(*) AS count
         FROM schedule_user
         WHERE schedule_user.schedule_id = schedule.schedule_id
           AND state=0))::integer AS state0, 
    (( SELECT count(*) AS count
         FROM schedule_user
         WHERE schedule_user.schedule_id = schedule.schedule_id
           AND state=1))::integer AS state1,
    (( SELECT count(*) AS count
         FROM schedule_user
         WHERE schedule_user.schedule_id = schedule.schedule_id
           AND state=2))::integer AS state2,          
    (( SELECT count(*) AS count
         FROM schedule_user
         WHERE schedule_user.schedule_id = schedule.schedule_id))::integer
       AS total
  FROM schedule

そのようなクエリを実行するより良い方法はありますか? 「状態」列へのインデックスを作成する必要がありますか? もしそうなら、それはどのように見えるべきですか?

4

3 に答える 3

6

ピボットテーブルを作成します。状態の可能な値をすべて事前に知っている場合にSQLで作成する簡単な方法は、sumandcaseステートメントを使用することです。

select schedule_id,
       sum(case state when 0 then 1 else 0 end) as state0,
       sum(case state when 1 then 1 else 0 end) as state1,
       sum(case state when 2 then 1 else 0 end) as state2,
       count(*) as total
from schedule_user
group by schedule_id;

もう1つの方法は、クロス集計テーブル関数を使用することです。

これらのどちらも、状態の値のセット(したがって、結果セットの列)を知らなくても問題を解決できません。

于 2013-03-21T18:27:26.873 に答える
3

私は試してみます

SELECT s.schedule_id,
       COUNT(CASE WHEN su.state = 0 THEN 1 END) AS state0,
       COUNT(CASE WHEN su.state = 1 THEN 1 END) AS state1,
       COUNT(CASE WHEN su.state = 2 THEN 1 END) AS state2,
       COUNT(su.state) AS total
  FROM schedule s
  LEFT
 OUTER
  JOIN schedule_user su
    ON su.schedule_id = s.schedule_id
 GROUP
    BY s.schedule_id
;
于 2013-03-21T18:25:10.460 に答える
0

この標準的なアプローチは、GROUP BYを使用したJOINよりもCASEを使用してSUM()を使用することです。

SELECT 
schedule.schedule_id AS id, 
SUM (case when state=0 then 1 else 0 end) AS state0, 
SUM (case when state=1 then 1 else 0 end) AS state1, 
SUM (case when state=2 then 1 else 0 end) AS state2, 
count(*) AS total
FROM schedule
LEFT JOIN schedule_user
  ON schedule_user.schedule_id = schedule.schedule_id
GROUP BY 1
于 2013-03-21T18:28:18.750 に答える