我正在尝试在MS SQL Server 2012中创建一个查询,该查询在数据库表中为我提供了count
,average
和一些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
226356
和377599
)。所以我需要一个产生以下结果的查询:
通缉结果
╔════════╦════════════╦══════╦════════╗
║ 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
计数很好,但AverageAge
,Male
和Female
值不正确。
我的问题是,我如何调整查询,以便检索 WANTED RESULT 设置中显示的值,如果这样的查询甚至可以开头?
答案 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