我有以下三个表,成员,年龄组和日志。我想知道每个年龄组中有多少人在给定的时间内访问系统。 以下是表格详情
tblMembers:
Member_Id,DOB,年龄
tblAgeGroup:
AgeGroup Id,AgeGroup_Des,minAge,maxAge,meanAge
tblLog:
Member_Id,AccessDate
因此,当管理员选择日期范围时,例如01/04/2014至30/04/2014
我需要显示类似于以下内容的输出:
年龄组用户数
15-25 -------------- 3
25-35 -------------- 2
我怎么也做不到。这是我到目前为止所做的事情
SELECT Member_Id, Age
FROM tblLog
JOIN tblMembers ON tblMembers.Member_Id = tblLog.Member_Id
WHERE AccessDate >= '2014-04-01'
AND AccessDate <= '2014-04-30'
GROUP BY Member_Id, Age
根据脚本,我可以列出Members_Id及其年龄。如何通过tblAgeGroup表中的组详细信息进行分组继续进行。
请建议我。感谢
答案 0 :(得分:1)
尝试
SELECT ag.AgeGroup_Des, count(1)
FROM tblLog l
INNER JOIN tblMembers m ON m.Member_Id = l.Member_Id
INNER JOIN tblAgeGroup ag ON ag.minAge <= m.Age and ag.maxAge > m.Age
WHERE AccessDate >= '2014-04-01'
AND AccessDate <= '2014-04-30'
GROUP BY ag.AgeGroup_Des
但是,当使用间隔加入时,正如我们在tblAgeGroup上所做的那样,测试我们是否获得正确的行数非常重要。
因此,我将运行以下查询,并验证它们确实返回相同数量的行:
SELECT COUNT(1)
FROM tblLog l
INNER JOIN tblMembers m ON m.Member_Id = l.Member_Id
--INNER JOIN tblAgeGroup ag ON ag.minAge <= m.Age and ag.maxAge > m.Age
WHERE AccessDate >= '2014-04-01'
AND AccessDate <= '2014-04-30'
和
SELECT COUNT(1)
FROM tblLog l
INNER JOIN tblMembers m ON m.Member_Id = l.Member_Id
INNER JOIN tblAgeGroup ag ON ag.minAge <= m.Age and ag.maxAge > m.Age
WHERE AccessDate >= '2014-04-01'
AND AccessDate <= '2014-04-30'
有两件事情在我脑海中浮现,在使用区间加入时可能会出错。
首先;如果没有唯一定义的间隔,则会多次返回每个成员。 例如,考虑包含tblAgeGroup ... ,minAge = 15 ,maxAge = 35 ... 和另一个条目: ... ,minAge = 20 ,maxAge = 25 ...
因此,年龄为21岁的成员将在两个时间间隔内返回,从而在您的计数中产生通货膨胀。
其次;如果未在tblMembers中定义Age,则将排除该行,但这可能是预期的,因为我们正在使用内部联接。 你可以通过以下方式解决这个问题:
SELECT ISNULL(ag.AgeGroup_Des, 'No group found') as AgeGroup_Des,
COUNT(1) as "AMT users"
FROM tblLog l
INNER JOIN tblMembers m ON m.Member_Id = l.Member_Id
LEFT JOIN tblAgeGroup ag ON ag.minAge <= m.Age and ag.maxAge > m.Age
WHERE AccessDate >= '2014-04-01'
AND AccessDate <= '2014-04-30'
GROUP BY ISNULL(ag.AgeGroup_Des, 'No group found')
ORDER BY 1
修改强> 添加了一个SQLFiddle来测试: http://sqlfiddle.com/#!6/137b8/5
小提琴中的查询是:
<强>构建强>
CREATE TABLE tblMembers
(
Member_ID int,
DOB date,
Age int
);
CREATE TABLE tblAgeGroup
(
[AgeGroup Id] int,
AgeGroup_Des varchar(16),
minAge int,
maxAge int,
meanAge float
);
CREATE TABLE tblLog
(
Member_id int,
AccessDate date
);
INSERT INTO tblMembers
(Member_ID, DOB, Age)
SELECT 1, '1991-03-22', 23
UNION ALL
SELECT 2, '2000-03-22', 14
UNION ALL
SELECT 3, '1981-03-22', 33
UNION ALL
SELECT 4, null, null;
INSERT INTO tblAgeGroup
([AgeGroup Id], AgeGroup_Des, minAge, maxAge, meanAge)
SELECT 1, '15-25', 15, 25, null
UNION ALL
SELECT 2, '10-15', 10, 15, null
UNION ALL
SELECT 3, '25-55', 25, 55, null;
INSERT INTO tblLog
(Member_id, AccessDate)
SELECT 1, GETDATE()
UNION ALL
SELECT 2, GETDATE()
UNION ALL
SELECT 1, '2014-04-02'
UNION ALL
SELECT 2, '2014-04-03'
UNION ALL
SELECT 2, '2014-04-03'
UNION ALL
SELECT 3, '2014-04-03'
UNION ALL
SELECT 4, '2014-04-03';
<强>查询:强>
-- First query: (exludes member 4, since no DOB is registered:
SELECT ag.AgeGroup_Des, COUNT(1)
FROM tblLog l
INNER JOIN tblMembers m ON m.Member_Id = l.Member_Id
INNER JOIN tblAgeGroup ag ON ag.minAge <= m.Age and ag.maxAge > m.Age
WHERE AccessDate >= '2014-04-01'
AND AccessDate <= '2014-04-30'
GROUP BY ag.AgeGroup_Des;
-- To validate that the counts are the same:
SELECT COUNT(1)
FROM tblLog l
INNER JOIN tblMembers m ON m.Member_Id = l.Member_Id
--INNER JOIN tblAgeGroup ag ON ag.minAge <= m.Age AND ag.maxAge > m.Age
WHERE AccessDate >= '2014-04-01'
AND AccessDate <= '2014-04-30';
-- Second validation:
-- Notice: this does return one less row, since we are using inner join,
-- and thus ommitting member 4
SELECT COUNT(1)
FROM tblLog l
INNER JOIN tblMembers m ON m.Member_Id = l.Member_Id
INNER JOIN tblAgeGroup ag ON ag.minAge <= m.Age AND ag.maxAge > m.Age
WHERE AccessDate >= '2014-04-01'
AND AccessDate <= '2014-04-30';
-- Last query, which includes members with no DOB registered,
-- as well as members that does not fall into any group:
SELECT ISNULL(ag.AgeGroup_Des, 'No group found') as AgeGroup_Des,
COUNT(1) as "AMT users"
FROM tblLog l
INNER JOIN tblMembers m ON m.Member_Id = l.Member_Id
LEFT JOIN tblAgeGroup ag ON ag.minAge <= m.Age AND ag.maxAge > m.Age
WHERE AccessDate >= '2014-04-01'
AND AccessDate <= '2014-04-30'
GRUOP BY ISNULL(ag.AgeGroup_Des, 'No group found')
ORDER BY 1;
2014-05-14:修改:
我在你的评论中看到,你还需要计算空组。为了做到这一点,我已经“反转”了from子句,因此我们从tblAgeGroup中选择所有,然后 left join 其他表。
另外,我假设您需要一些日志条目,但在阅读评论后,我看到您要求不同的用户。我已相应地更改了查询。
select
ag.AgeGroup_Des
, count(l.Member_ID) as [AMT Log entries]
, count(distinct l.Member_ID) as [AMT distinct members]
from tblAgeGroup ag
left join tblMembers m on ag.minAge <= m.Age and ag.maxAge > m.Age
left join tblLog l on l.Member_id = m.Member_ID
group by isnull(ag.AgeGroup_Des, 'No group found')
order by 1
;
返回
AgeGroup_Des AMT Log entries AMT distinct members
10-15 3 1
15-25 2 1
25-55 1 1
55-65 0 0
但是,这种方法确实忽略了没有注册DOB /年龄的每个成员。 如果我们想要包含这些内容,我们需要将查询编辑为完全外部联接:
select
isnull(ag.AgeGroup_Des, 'No group found') as AgeGroup_Des
, count(l.Member_ID) as [AMT Log entries]
, count(distinct l.Member_ID) as [AMT distinct members]
from tblAgeGroup ag
full outer join tblMembers m on ag.minAge <= m.Age and ag.maxAge > m.Age
full outer join tblLog l on l.Member_id = m.Member_ID
group by isnull(ag.AgeGroup_Des, 'No group found')
order by 1
;
返回
AgeGroup_Des AMT Log entries AMT distinct members
10-15 3 1
15-25 2 1
25-55 1 1
55-65 0 0
No group found 1 1
请在此处查看更新的小提琴:http://sqlfiddle.com/#!6/d8733/5
答案 1 :(得分:0)
SELECT usr_type, SUM(_15_25 + _25_35) AS qty
FROM
(SELECT CASE
WHEN age>=15 AND age<25 THEN '15-25'
WHEN age>=25 AND age<=35 THEN '25-35'
ELSE 'other'
END AS usr_type,
CASE
WHEN age>= 15 AND age < 25 THEN 1
ELSE 0
END AS _15_25,
CASE
WHEN age >= 25 AND age <= 35 THEN 1
ELSE 0
END AS _25_35
Age
FROM tblLog
JOIN tblMembers ON tblMembers.Member_Id = tblLog.Member_Id
WHERE AccessDate >= '2014-04-01'
AND AccessDate <= '2014-04-30'
) T
GROUP BY usr_type
尝试这种逻辑解决方案。
答案 2 :(得分:0)
SELECT minAge, maxAge, count(*) as "No of Users"
FROM tblAgeGroup g
INNER JOIN tblMembers m ON Age BETWEEN minAge AND maxAge
INNER JOIN tblLog l ON m.Member_ID = l.Member_ID
WHERE AccessDate BETWEEN '2014-04-01' and '2014-04-30'
GROUP BY minAge, maxAge
ORDER BY minAge, maxAge