2014-10-17 57 views
1

我有這個表代表小組成員的人:MAX與條件

+----+-----------+----------+------------+------------+ 
| id | person_id | group_id | from  | to   | 
+----+-----------+----------+------------+------------+ 
| 1 | 1   | 1  | 2014-10-13 | 2014-10-20 | 
+----+-----------+----------+------------+------------+ 
| 2 | 1   | 1  | 2014-10-17 | 2014-10-31 | 
+----+-----------+----------+------------+------------+ 
| 3 | 1   | 1  | 2014-10-01 | 2014-10-15 | 
+----+-----------+----------+------------+------------+ 
| 4 | 1   | 2  | 2014-11-01 | 2014-12-01 | 
+----+-----------+----------+------------+------------+ 

我想選擇爲每個組和個人,並顯示如果它是當前處於活動狀態的成員加起來。如果當前與「活躍」會員資格重疊的「非活躍」會員資格沒有合併到結果中(如果可能的話,這樣也不錯)。今天是二〇一四年十月十七日,因此結果在這種情況下設置應爲:

+-----------+----------+------------+------------+----------+ 
| person_id | group_id | from  | until  | status | 
+-----------+----------+------------+------------+----------+ 
| 1   | 1  | 2014-10-13 | 2014-10-31 | ACTIVE | 
+-----------+----------+------------+------------+----------+ 
| 1   | 2  | NULL  | NULL  | INACTIVE | 
+-----------+----------+------------+------------+----------+ 

因此對於所使用的值組1中第1行第2行是fromuntil和行3被排除,即使它的until與第1行中的from重疊。我寧願如果使用第3行中的from來代替,但如果結果集如上所示則沒問題。第2組無效,因爲它沒有任何與from < NOW()和until> NOW()的行。

現在我有這樣的:

CREATE TEMPORARY TABLE combinedRows ENGINE = MEMORY 
SELECT 
    `person_id`, 
    `group_id`, 
    MIN(`from`) AS `from`, 
    MAX(`until`) AS `until`, 
    'ACTIVE' AS `status` 
FROM 
    `memberships` 
WHERE 
    `person_id` = @updated_person 
    AND `group_id` = @updated_bgroup 
    AND `from` < NOW() 
    AND `until` > NOW() 
GROUP BY 
    `person_id`, 
    `group_id`; 

其次是INSERT INTO忽略選擇combinedRows倒...基本上我想要做同樣的事情在一個單一的查詢(由於性能原因)。相當於這個「僞代碼」的東西:

CREATE TEMPORARY TABLE combinedRows ENGINE = MEMORY 
SELECT 
    `person_id`, 
    `group_id`, 
    MIN(`from` WHERE `from` < NOW() and `until` > NOW()) DEFAULT NULL AS `from`, 
    MAX(`until` WHERE `from` < NOW() and `until` > NOW()) DEFAULT NULL AS `until`, 
    IF(*something*, 'ACTIVE', 'INACTIVE') AS `status` 
FROM 
    `memberships` 
WHERE 
    `person_id` = @updated_person 
    AND `group_id` = @updated_bgroup 
GROUP BY 
    `person_id`, 
    `group_id`; 

這是可能嗎?或者我應該忘記它,不要擔心表現?還是應該改變數據庫設計?

回答

2
SELECT 
    `person_id`, 
    `group_id`, 
    MIN(CASE WHEN `from` < NOW() and `until` > NOW() THEN `from` ELSE NULL END) AS `from`, 
    MAX(CASE WHEN `from` < NOW() and `until` > NOW() THEN `until` ELSE NULL END) AS `until`, 
    MIN(CASE WHEN `from` < NOW() and `until` > NOW() THEN 'ACTIVE' ELSE 'INACTIVE' END) AS `status` 
FROM 
    `memberships` 
WHERE 
    `person_id` = @updated_person 
    AND `group_id` = @updated_bgroup 
GROUP BY 
    `person_id`, 
    `group_id`; 

說明:

你可以把聚合函數的表達式(MAXMIN,...)。 NULL值被忽略,並且MIN(或MAX)從不是NULL的值計算。

如果你看看:

MIN(CASE WHEN `from` < NOW() and `until` > NOW() THEN 'ACTIVE' ELSE 'INACTIVE' END) 

那麼這裏的竅門是:如果有滿足條件的行,然後「ACTIVE」被返回,因爲當作爲字符串比較「ACTIVE」小於「無效」 。

+0

啊,很酷,它工作:)謝謝。 – moggizx 2014-10-17 10:30:18