2013-03-21 94 views
1

我有這個表:如何查詢多個COUNT(*)具有良好的性能

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 
) 
 
schedule 
------------------------- 
|schedule_id |date  | 
|------------+------------| 
|1   |'2013-10-10'| 
|2   |'2013-10-20'| 
|3   |'2013-08-13'| 
------------------------- 

schedule_user 
----------------------------------- 
|schedule_user_id|schedule_id |state| 
|----------------+------------+-----| 
|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 | 
----------------------------------- 

而且我希望有一個表是這樣的:

 
characteristic 
--------------------------------------- 
|schedule_id |state0|state1|state2|total| 
|------------+------+------+------+-----| 
|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 

有沒有更好的方法來執行這樣的查詢? 我應該創建一個'狀態'列索引?如果是這樣,它應該是什麼樣子?

+1

你想要做什麼是一個支點。 – Kermit 2013-03-21 18:23:47

回答

4

你想使數據透視表。如果事先知道所有可能的狀態值,則使用sumcase語句可以簡單地在SQL中創建一個。

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; 

另一種方法是使用crosstab表函數。

這些都不會讓你不知道狀態值的集合(因此也就是結果集中的列)。

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 
; 
0

THS標準方法是在JOIN與CASE使用SUM()與GROUP BY:

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 
相關問題