-1

看到这个小提琴。我有一个问题表,其中每个问题都属于一个类别,我必须找到每个类别的用户平均值。我认为它工作正常,但我想添加一个总数,显示每个用户的平均值中包含的答案总数。我不知道要在 where 子句中放入什么来实际返回每个用户的问题总数。无论我包含用户 ID、QID 还是选项,它都给了我天文数字。

查询 SQL:

DECLARE @tblTmpCatStats TABLE (userid NVARCHAR(10),cat1_mean FLOAT,cat2_mean FLOAT,cat3_mean FLOAT,cat4_mean FLOAT,N FLOAT)
INSERT INTO @tblTmpCatStats SELECT d.userid
    ,AVG(CAST(c1.choice AS FLOAT))
    ,AVG(CAST(c2.choice AS FLOAT))
    ,AVG(CAST(c3.choice AS FLOAT))
    ,AVG(CAST(c4.choice AS FLOAT))
    ,COUNT(d.userid)
FROM tblTmpDemographics d
JOIN tblTmpDemographics c1 ON d.userid = c1.userid
JOIN tblTmpDemographics c2 ON d.userid = c2.userid
JOIN tblTmpDemographics c3 ON d.userid = c3.userid
JOIN tblTmpDemographics c4 ON d.userid = c4.userid
WHERE c1.QID IN ('1','5')
AND c2.QID IN ('2','6')
AND c3.QID IN ('3','7')
AND c4.QID IN ('4','8')
GROUP BY d.userid
SELECT * FROM @tblTmpCatStats

我正在尝试使 N 等于 AVG 中包含的选择总数

设置 SQL:

CREATE TABLE tblTmpDemographics (userid NVARCHAR(10),QID INT,choice NVARCHAR(1000))
INSERT INTO tblTmpDemographics (userid,QID,choice)
SELECT 'user1',1,'5' UNION ALL SELECT 'user1',2,'3' UNION ALL
SELECT 'user1',3,'4' UNION ALL SELECT 'user1',4,'5' UNION ALL
SELECT 'user1',5,'5' UNION ALL SELECT 'user1',6,'3' UNION ALL
SELECT 'user1',7,'4' UNION ALL SELECT 'user1',8,'5' UNION ALL

SELECT 'user2',1,'3' UNION ALL SELECT 'user2',2,'2' UNION ALL
SELECT 'user2',3,'3' UNION ALL SELECT 'user2',4,'5' UNION ALL
SELECT 'user2',5,'3' UNION ALL SELECT 'user2',6,'2' UNION ALL
SELECT 'user2',7,'3' UNION ALL SELECT 'user2',8,'5' UNION ALL

SELECT 'user3',1,'2' UNION ALL SELECT 'user3',2,'1' UNION ALL
SELECT 'user3',3,'5' UNION ALL SELECT 'user3',4,'5' UNION ALL
SELECT 'user3',5,'2' UNION ALL SELECT 'user3',6,'1' UNION ALL
SELECT 'user3',7,'5' UNION ALL SELECT 'user3',8,'5' UNION ALL

SELECT 'user4',1,'4' UNION ALL SELECT 'user4',2,'3' UNION ALL
SELECT 'user4',3,'3' UNION ALL SELECT 'user4',4,'5' UNION ALL
SELECT 'user4',5,'4' UNION ALL SELECT 'user4',6,'3' UNION ALL
SELECT 'user4',7,'3' UNION ALL SELECT 'user4',8,'5' GO

为什么它返回 128 而不是 8?

4

4 回答 4

2

试试这个:

SELECT d.userid
    ,AVG(CAST(c1.choice AS FLOAT))
    ,AVG(CAST(c2.choice AS FLOAT))
    ,AVG(CAST(c3.choice AS FLOAT))
    ,AVG(CAST(c4.choice AS FLOAT))
    , d.cnt
FROM
(
  SELECT userid, count(*) cnt
  from tblTmpDemographics
  group by userid
) d
INNER JOIN tblTmpDemographics c1 
  ON d.userid = c1.userid
INNER JOIN tblTmpDemographics c2 
  ON d.userid = c2.userid
INNER JOIN tblTmpDemographics c3 
  ON d.userid = c3.userid
INNER JOIN tblTmpDemographics c4 
  ON d.userid = c4.userid
WHERE c1.QID IN ('1','5')
  AND c2.QID IN ('2','6')
  AND c3.QID IN ('3','7')
  AND c4.QID IN ('4','8')
GROUP BY d.userid,  d.cnt

请参阅带有演示的 SQL Fiddle

于 2012-08-22T15:51:23.030 回答
2

您选择获取结果的方法无法为您带来正确的计数,这仅仅是因为您的所有联接,即使它们被进一步过滤,也可能(其中一些最终会)导致每行有多个匹配项,并且反过来,在中间结果集中产生迷你笛卡尔积,最终被聚合。

@bluefeet 的建议有效,因为计数是单独计算的,但它仍然不能解决一般的笛卡尔积效应。您的平均值之所以正确,仅仅是因为它们是平均值,而不是计数总和。本质上,它们当然是总和除以计数,并且由于两个操作数的因数相同,因此无论笛卡尔积的影响如何,您的平均值最终都是正确的。但是,如果您尝试对您的choice值进行 SUM 或 COUNT,您将再次看到不正确的结果。

您可以改为使用条件聚合,如下所示:

SELECT
  userid,
  cat1_mean = AVG(CASE WHEN QID IN (1, 5) THEN CAST(choice AS float) END),
  cat2_mean = AVG(CASE WHEN QID IN (2, 6) THEN CAST(choice AS float) END),
  cat3_mean = AVG(CASE WHEN QID IN (3, 7) THEN CAST(choice AS float) END),
  cat4_mean = AVG(CASE WHEN QID IN (4, 8) THEN CAST(choice AS float) END),
  N = COUNT(*)
FROM tblTmpDemographics
GROUP BY userid
;

或者您可以使用 SQL Server 的PIVOT功能,如下所示:

SELECT
  userid,
  cat1_mean,
  cat2_mean,
  cat3_mean,
  cat4_mean,
  N
FROM (
  SELECT
    userid,
    choice = CAST(choice AS float),
    QuestionGroup = CASE
      WHEN QID IN (1, 5) THEN 'cat1_mean'
      WHEN QID IN (2, 6) THEN 'cat2_mean'
      WHEN QID IN (3, 7) THEN 'cat3_mean'
      WHEN QID IN (4, 8) THEN 'cat4_mean'
    END,
    N = COUNT(*) OVER (PARTITION BY userid)
  FROM tblTmpDemographics
) s
PIVOT (
  AVG(choice) FOR QuestionGroup IN (
    cat1_mean,
    cat2_mean,
    cat3_mean,
    cat4_mean
  )
) p
;

或像这样(与以前相同,但使用公用表表达式):

WITH marked AS (
  SELECT
    userid,
    choice = CAST(choice AS float),
    QuestionGroup = CASE
      WHEN QID IN (1, 5) THEN 'cat1_mean'
      WHEN QID IN (2, 6) THEN 'cat2_mean'
      WHEN QID IN (3, 7) THEN 'cat3_mean'
      WHEN QID IN (4, 8) THEN 'cat4_mean'
    END,
    N = COUNT(*) OVER (PARTITION BY userid)
  FROM tblTmpDemographics
)
SELECT
  userid,
  cat1_mean,
  cat2_mean,
  cat3_mean,
  cat4_mean,
  N
FROM marked
PIVOT (
  AVG(choice) FOR QuestionGroup IN (
    cat1_mean,
    cat2_mean,
    cat3_mean,
    cat4_mean
  )
) p
;

这两种方法都可以在 SQL Fiddle 进行测试和使用:

于 2012-08-24T12:01:46.220 回答
1

这是实现它的一种略显粗糙的方式,但改变了

COUNT(d.userID)

COUNT(distinct d.qid)

为每个用户提供 8 个计数。

于 2012-08-22T15:30:02.400 回答
0
select userid, count(userid) cnt from tblTmpDemographics group by userid

这显示 8 - 您必须运行两次插入。

于 2012-08-22T15:29:18.683 回答