我有这个表代表人群中的成员身份:
+----+-----------+----------+------------+------------+
| 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 |
+----+-----------+----------+------------+------------+
我想为每个群组和个人选择合并的成员资格,并显示当前是否有效的状态。如果当前与“活动”成员资格重叠的“非活动”成员资格不会在结果中合并,那就没关系了(尽管如果可能的话也会很好)。今天是2014-10-17,所以在这种情况下的结果集应该是:
+-----------+----------+------------+------------+----------+
| person_id | group_id | from | until | status |
+-----------+----------+------------+------------+----------+
| 1 | 1 | 2014-10-13 | 2014-10-31 | ACTIVE |
+-----------+----------+------------+------------+----------+
| 1 | 2 | NULL | NULL | INACTIVE |
+-----------+----------+------------+------------+----------+
因此,对于第1组,使用的值是第1行from
,第2行until
,第3行被排除,即使其until
与from
重叠第1行。我更喜欢使用第3行中的from
代替,但如果结果集如上所示则没问题。第2组处于非活动状态,因为它没有任何行from
<现在()和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 IGNORE INTO combinedRows SELECT inversed ...基本上我想在一个查询中做同样的事情(出于性能原因)。相当于这个“伪代码”的东西:
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`;
这可能吗?或者我应该忘记它并且不担心性能?或者我应该以某种方式更改数据库设计?
答案 0 :(得分: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`;
说明:
您可以将任何表达式放在聚合函数中(MAX
,MIN
,...)。 NULL
值被忽略,MIN
(或MAX
)的值是根据NULL
的值计算的。
如果你看一下:
MIN(CASE WHEN `from` < NOW() and `until` > NOW() THEN 'ACTIVE' ELSE 'INACTIVE' END)
那么这里的技巧是:如果有满足条件的行,则返回'ACTIVE',因为'ACTIVE'在作为字符串进行比较时小于'INACTIVE'。