我试图从三个表中获取访客的年龄: 按客户ID包含viist日期的访问,以及 拥有客户端ID的客户端,以及 拥有诊所ID的诊所。
这是我的sql语句:
DECLARE @Clinicname nvarchar(50)
SET @Clinicname='First Clinic'
SELECT CASE
WHEN DATEDIFF(YEAR, c.BirthDate, MIN(v.Date)) <= 10 THEN '1-10'
WHEN DATEDIFF(YEAR, c.BirthDate, MIN(v.Date)) <= 20 THEN '11-20'
WHEN DATEDIFF(YEAR, c.BirthDate, MIN(v.Date)) <= 30 THEN '21-30'
WHEN DATEDIFF(YEAR, c.BirthDate, MIN(v.Date)) <= 40 THEN '31-40'
WHEN DATEDIFF(YEAR, c.BirthDate, MIN(v.Date)) <= 50 THEN '41-50'
WHEN DATEDIFF(YEAR, c.BirthDate, MIN(v.Date)) <= 60 THEN '51-60'
WHEN DATEDIFF(YEAR, c.BirthDate, MIN(v.Date)) <= 70 THEN '61-70'
WHEN DATEDIFF(YEAR, c.BirthDate, MIN(v.Date)) <= 80 THEN '71-80'
ELSE '81+'
END AS age,
COUNT(*) AS n
FROM Visit v
INNER JOIN Client c ON v.ClientID = c.ClientID
INNER JOIN Clinic r ON v.ClinicId = r.ClinicId
WHERE r.Name IN (@Clinicname)
GROUP BY CASE
WHEN DATEDIFF(YEAR, c.BirthDate, MIN(v.Date)) <= 10 THEN '1-10'
WHEN DATEDIFF(YEAR, c.BirthDate, MIN(v.Date)) <= 20 THEN '11-20'
WHEN DATEDIFF(YEAR, c.BirthDate, MIN(v.Date)) <= 30 THEN '21-30'
WHEN DATEDIFF(YEAR, c.BirthDate, MIN(v.Date)) <= 40 THEN '31-40'
WHEN DATEDIFF(YEAR, c.BirthDate, MIN(v.Date)) <= 50 THEN '41-50'
WHEN DATEDIFF(YEAR, c.BirthDate, MIN(v.Date)) <= 60 THEN '51-60'
WHEN DATEDIFF(YEAR, c.BirthDate, MIN(v.Date)) <= 70 THEN '61-70'
WHEN DATEDIFF(YEAR, c.BirthDate, MIN(v.Date)) <= 80 THEN '71-80'
ELSE '81+'
END
这是错误: 不能在GROUP BY子句列表的组表达式中使用聚合或子查询。
当我用GETDATE()替换MIN(v.Date)时,它可以工作。
答案 0 :(得分:2)
一些猜测,基于松散的规格,未知版本等。一条建议:DATEDIFF(YEAR
不是计算年龄的可靠方法。想想这个人的生日是在12月并且他们在1月访问的情况,反之亦然。 DATEDIFF
只计算已经越过了多少边界,并不关心这个人的生日是否已经发生。
您可能可能会将这些查询片段中的一些组合在一起,但将它们分块可能会使逻辑更容易消化。
SQL Server 2005 +
;WITH vis AS
(
SELECT
v.ClientId,
FirstVisit = MIN(v.[Date]),
NumVisits = COUNT(*)
FROM dbo.Visit AS v
INNER JOIN dbo.Clinic AS c
ON c.ClinicId = v.ClinicId
WHERE c.Name IN (@Clinicname)
GROUP BY v.ClientId
),
ages AS (
SELECT
v.ClientId,
rough_age = DATEDIFF(YEAR, c.BirthDate, v.FirstVisit),
v.NumVisits
FROM vis AS v
INNER JOIN dbo.Client AS c
ON v.ClientId = c.ClientId
),
cats([group], numVisits) AS (
SELECT
CASE WHEN rough_age/10 > 8 THEN '81+' ELSE
CONVERT(VARCHAR(32), ((rough_age/10)+1)*10-9) + '-'
+ CONVERT(VARCHAR(12), ((rough_age/10)+1)*10) END,
numVisits
FROM ages
)
SELECT [group], NumClients = COUNT(*), NumVisits = SUM(numVisits)
FROM cats
GROUP BY [group];
SQL Server 2000
SELECT [group], NumClients = COUNT(*), NumVisits = SUM(numVisits)
FROM (
SELECT
[group] = CASE WHEN rough_age/10 > 8 THEN '81+' ELSE
CONVERT(VARCHAR(32), ((rough_age/10)+1)*10-9) + '-'
+ CONVERT(VARCHAR(12), ((rough_age/10)+1)*10) END,
numVisits
FROM
(
SELECT
v.ClientId,
rough_age = DATEDIFF(YEAR, c.BirthDate, v.FirstVisit),
v.NumVisits
FROM
(
SELECT
v.ClientId,
FirstVisit = MIN(v.[Date]),
NumVisits = COUNT(*)
FROM dbo.Visit AS v
INNER JOIN dbo.Clinic AS c
ON c.ClinicId = v.ClinicId
WHERE c.Name = @Clinicname
GROUP BY v.ClientId
) AS v
INNER JOIN dbo.Client AS c
ON v.ClientId = c.ClientId
) AS ages
) AS cats
GROUP BY [group];
答案 1 :(得分:0)
您可以使用内部查询解决分组问题。在任何情况下,这都是首选,因为您不必复制存储逻辑。
我也删除了MIN(v.Date),因为我认为这不是必要的。
DECLARE
@Clinicname nvarchar(50);
SET @Clinicname='First Clinic'
select age, count(*) from
(
SELECT CASE
WHEN DATEDIFF(YEAR, c.BirthDate, v.Date) <= 10 THEN '1-10'
WHEN DATEDIFF(YEAR, c.BirthDate, v.Date) <= 20 THEN '11-20'
WHEN DATEDIFF(YEAR, c.BirthDate, v.Date) <= 30 THEN '21-30'
WHEN DATEDIFF(YEAR, c.BirthDate, v.Date) <= 40 THEN '31-40'
WHEN DATEDIFF(YEAR, c.BirthDate, v.Date) <= 50 THEN '41-50'
WHEN DATEDIFF(YEAR, c.BirthDate, v.Date) <= 60 THEN '51-60'
WHEN DATEDIFF(YEAR, c.BirthDate, v.Date) <= 70 THEN '61-70'
WHEN DATEDIFF(YEAR, c.BirthDate, v.Date) <= 80 THEN '71-80'
ELSE '81+'
END AS age
FROM Visit v
INNER JOIN Client c ON v.ClientID = c.ClientID
INNER JOIN Clinic r ON v.ClinicId = r.ClinicId
WHERE r.Name IN (@Clinicname)
) t group by age;