在我的J2EE Web应用程序中,我需要生成一个条形图,表示具有特定users
的系统中alerts
的百分比。 (编辑 - 我忘了提及,该图表仅处理与每个用户的第一个situation
相关联的提醒,因此min(date)
)。
我的数据库模式的简化(但结构相似)版本如下:
users { id, name }
situations { id, user_id, date }
alerts { id, situation_id, alertA, alertB }
其中users
至situations
为1-n,situations
至alerts
为1。
我省略了数据类型,但警报(alertA和B)是布尔值。在我的实际案例中,有许多此类警报(30-ish)。
到目前为止,这是我提出的:
select sum(alerts.alertA), sum(alerts.alertB)
form alerts, (
select id, min(date)
from situations
group by user_id) as situations
where situations.id = alerts.situation_id;
然后将这些总和除以
select count(users.id) from users;
这似乎远非理想。
关于如何改进查询的建议/建议将是最受欢迎的(或者我可能需要重新考虑我的数据库架构)......
谢谢,
安东尼
PS。每当警报表更新时,我还在考虑使用触发器刷新特定于图表的表格,但我猜这是一个不同查询的主题(如果结果有问题)。
答案 0 :(得分:2)
首先,再次考虑您的架构。您将收到许多不同的警报,并且您可能不希望为每个警报添加一个列。
请考虑将您的alerts
表更改为{ id, situation_id, type, value }
,其中type
为(A,B,C,....)
,value
将是您的布尔值。
您计算百分比的任务将分成:
(1)统计用户总数:
SELECT COUNT(id) AS total FROM users
(2)找出每个用户的“第一”情况:
SELECT situations.id, situations.user_id
-- selects the minimum date for every user_id
FROM (SELECT user_id, MIN(date) AS min_date
FROM situations
GROUP BY user_id) AS first_situation
-- gets the situations.id for user with minimum date
JOIN situations ON
first_situation.user_id = situations.user_id AND
first_situation.min_date = situations.date
-- limits number of situations per user to 1 (possible min_date duplicates)
GROUP BY user_id
(3)计算在子查询中至少有一种情况设置了警报的用户:
SELECT
alerts.type,
COUNT(situations.user_id)
FROM ( ... situations.user_id, situations.id ... ) AS situations
JOIN alerts ON
situations.id = alerts.situation_id
WHERE
alerts.value = 1
GROUP BY
alerts.type
将这三个步骤放在一起得到类似的东西:
SELECT
alerts.type,
COUNT(situations.user_id)/users.total
FROM (SELECT situations.id, situations.user_id
FROM (SELECT user_id, MIN(date) AS min_date
FROM situations
GROUP BY user_id) AS first_situation
JOIN situations ON
first_situation.user_id = situations.user_id AND
first_situation.min_date = situations.date
GROUP BY user_id
) AS situations
JOIN alerts ON
situations.id = alerts.situation_id
JOIN (SELECT COUNT(id) AS total FROM users) AS users
WHERE
alerts.value = 1
GROUP BY
alerts.type
所有查询都是从我的脑子里写的,没有经过测试。即使他们不能完全像那样工作,你仍然应该得到这个想法!