如何在一个MS SQL查询中获得不同的平均值和总和值?

时间:2014-06-24 13:28:10

标签: sql sql-server database sql-server-2012 distinct

我正在尝试在MS SQL Server 2012中创建一个查询,该查询在数据库表中为我提供了countaverage和一些sum个不同记录的值。我会尽力解释我的情况和我的愿望。如果仍有不清楚的地方或需要一些额外信息,请告诉我。

让下表TEMP包含10条记录:

表格

╔════════╦═════════════╦════════╦═══════════╗
║ Number ║ DateOfBirth ║ Gender ║ Activity  ║
╠════════╬═════════════╬════════╬═══════════╣
║ 191806 ║ 1940-08-31  ║ F      ║ AMADMIN   ║
║ 196484 ║ 1940-09-23  ║ F      ║ AMHOST    ║
║ 199480 ║ 1949-10-16  ║ F      ║ AMTRAINER ║
║ 201089 ║ 1947-04-08  ║ M      ║ AMTRAINER ║
║ 204528 ║ 1950-05-02  ║ F      ║ AMHOST    ║
║ 226356 ║ 1966-04-12  ║ M      ║ AMADMIN   ║
║ 226356 ║ 1966-04-12  ║ M      ║ AMHOST    ║
║ 377599 ║ 1985-05-15  ║ F      ║ AMADMIN   ║
║ 377599 ║ 1985-05-15  ║ F      ║ AMHOST    ║
║ 395809 ║ 1980-03-03  ║ F      ║ AMADMIN   ║
╚════════╩═════════════╩════════╩═══════════╝

现在,请考虑运行以下查询:

SQL

  SELECT COUNT([Number]) AS Number, ROUND(AVG(CAST(DATEDIFF(DAY, [DateOfBirth], GETDATE()) / 365.2425 AS FLOAT)), 1) AS AverageAge,
    SUM(CASE WHEN [Gender] = 'M' THEN 1 ELSE 0 END) AS Male,
    SUM(CASE WHEN [Gender] = 'F' THEN 1 ELSE 0 END) AS Female
  FROM [TEMP]
  WHERE [Activity] IN ('AMHOST', 'AMADMIN', 'AMTRAINER')

此查询将为我提供以下结果:

RESULT

╔════════╦════════════╦══════╦════════╗
║ Number ║ AverageAge ║ Male ║ Female ║
╠════════╬════════════╬══════╬════════╣
║     10 ║ 57,3       ║    3 ║      7 ║
╚════════╩════════════╩══════╩════════╝

到目前为止一切顺利!但现在是棘手的部分。我真正想要的是表中所有distinct条记录的结果。这意味着计算所有人的平均年龄和男/女人数减去两个“双人”(Number 226356377599)。所以我需要一个产生以下结果的查询:

通缉结果

╔════════╦════════════╦══════╦════════╗
║ Number ║ AverageAge ║ Male ║ Female ║
╠════════╬════════════╬══════╬════════╣
║      8 ║ 56,9       ║    2 ║      6 ║
╚════════╩════════════╩══════╩════════╝

我知道如何获取一条查询的distinct条记录,如下所示:

SQL

  SELECT COUNT(DISTINCT([Number])) AS Number, ROUND(AVG(CAST(DATEDIFF(DAY, [DateOfBirth], GETDATE()) / 365.2425 AS FLOAT)), 1) AS AverageAge,
    SUM(CASE WHEN [Gender] = 'M' THEN 1 ELSE 0 END) AS Male,
    SUM(CASE WHEN [Gender] = 'F' THEN 1 ELSE 0 END) AS Female
  FROM [TEMP]
  WHERE [Activity] IN ('AMHOST', 'AMADMIN', 'AMTRAINER')

但这会产生:

RESULT

╔════════╦════════════╦══════╦════════╗
║ Number ║ AverageAge ║ Male ║ Female ║
╠════════╬════════════╬══════╬════════╣
║      8 ║ 57,3       ║    3 ║      7 ║
╚════════╩════════════╩══════╩════════╝

现在Number计数很好,但AverageAgeMaleFemale值不正确。

我的问题是,我如何调整查询,以便检索 WANTED RESULT 设置中显示的值,如果这样的查询甚至可以开头?

3 个答案:

答案 0 :(得分:1)

由于活动未出现在任何聚合函数中,您只需从结果中对此进行折扣,并使用子查询在聚合之前获取不同的记录,然后将COUNT(DISTINCT CASE..应用于您的男性/女性计数:

SELECT  COUNT(DISTINCT [Number]) AS Number, 
        ROUND(AVG(CAST(DATEDIFF(DAY, [DateOfBirth], GETDATE()) / 365.2425 AS FLOAT)), 1) AS AverageAge,
        COUNT(DISTINCT CASE WHEN [Gender] = 'M' THEN [Number] END) AS Male,
        COUNT(DISTINCT CASE WHEN [Gender] = 'F' THEN [Number] END) AS Female
FROM    (   SELECT  DISTINCT Number, DateOfBirth, Gender
            FROM    [sw_test].[dbo].[TEMP]
            WHERE   [Activity] IN ('AMHOST', 'AMADMIN', 'AMTRAINER')
        ) AS t;

<强> Example on SQL Fiddle

答案 1 :(得分:1)

您的查询没有解决问题,因为您只告诉sql使用其中一列(数字)的不同数据点。当sql移出括号并继续计算下一列时,它不再使用distinct命令。

为了解决您的问题,我建议使用子查询。还有其他方法可以做到这一点,但我相信子查询是你最好的选择,因为你可以先过滤数据,然后根据唯一的数据点进行数学运算。并非数据点中的所有列都在具有重复数字的行中重复。但是,这只在活动列中(我们可以忽略它,因为在计算中没有必要)。我将假设性别和出生日期将始终相同。现在,您的查询将如下所示:

SELECT COUNT(DISTINCT(t.Number)) AS Number, ROUND(AVG(CAST(DATEDIFF(DAY, t.DateOfBirth, GETDATE()) / 365.2425 AS FLOAT)), 1) AS AverageAge,
    SUM(CASE WHEN t.Gender = 'M' THEN 1 ELSE 0 END) AS Male,
    SUM(CASE WHEN t.Gender = 'F' THEN 1 ELSE 0 END) AS Female
From
(   Select t.number, t.DateOfBirth, t.Gender
    From temp t
    Where activity in ('AMHOST', 'AMADMIN', 'AMTRAINER')
    Group by t.number, t.DateOfBirth, t.Gender) t

答案 2 :(得分:1)

此查询有效。做了一个子选择来获得基础。

SELECT COUNT([Number]) AS Number, ROUND(AVG(CAST(DATEDIFF(DAY, [DateOfBirth], GETDATE()) / 365.2425 AS FLOAT)), 1) AS AverageAge,
SUM(CASE WHEN [Gender] = 'M' THEN 1 ELSE 0 END) AS Male,
SUM(CASE WHEN [Gender] = 'F' THEN 1 ELSE 0 END) AS Female
FROM 
  (SELECT DISTINCT Number, DateOfBirth, Gender 
   FROM temp where [Activity] IN ('AMHOST', 'AMADMIN', 'AMTRAINER')) a