SQL按案例分组

SQL按案例分组,sql,sql-server,tsql,group-by,Sql,Sql Server,Tsql,Group By,我试图从三个表中获得访客的年龄: 按客户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 DATED

我试图从三个表中获得访客的年龄: 按客户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 
DECLARE@Clinicname-nvarchar(50)
设置@Clinicname='First Clinic'
选择案例

当DATEDIFF(YEAR,c.BirthDate,MIN(v.Date))时,您可以使用内部查询绕过分组问题。这在任何情况下都是可取的,因为您不必重复bucketing逻辑

我还删除了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;
声明
@临床名称nvarchar(50);
设置@Clinicname='First Clinic'
从中选择年龄、计数(*)
(
选择案例

当DATEDIFF(年份、c.生日、v.日期)时,根据松散的规格、未知版本等进行一些猜测。一条建议:
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];   

你想实现什么?我想实现的是计算人的年龄。例如,出生日期是1950年1月1日,探视日期是2011年1月1日,我想DATEDIFF可以做到。啊哈。所以你真的不需要一分钟。只要v。Date@Andrew,我认为需要的是他们第一次就诊时的年龄,而不是每次就诊时的年龄。请指定SQL Server的版本以及输出的性质。是否希望一列中第一次访问的人数为1-10人,另一列中为11-20人,或者每行的列中仅包含计数和标签?是计数(*)应该代表一个年龄组的就诊次数、客户数量、诊所数量、客户就诊次数?样本数据和预期结果将大大有助于说明您正在努力实现的目标。目前还不清楚,我们中的任何人都无法弄清楚。谢谢安德鲁,我得到了以下错误r Msg 156,级别15,状态1,第18行关键字“FROM”附近的语法不正确。@user373721:这是因为在age之后有一个逗号。我现在已修复了答案中的语法。谢谢,现在我收到了此错误消息8120,级别16,状态1,第7行列“Client.BirthDate”在选择列表中无效,因为它不包含在任何聚合列表中ction或GROUP BY子句。我使用MIN来获取第一次就诊的日期TANDREW,这将是任何客户到任何诊所的所有就诊的最小值,而这不是原始查询试图做的。非常感谢Aaron提供的解决方案以及解释日期差异。