如何在sql中获得每个答案的百分比?

时间:2016-02-12 06:17:56

标签: sql sql-server tsql

enter image description here

我有一个民意调查系统。我使用此查询来计算每个问题的答案。如何获得每个回答选项的百分比如下:

question 1 ---> option1=20.13 % ---> option2=79.87 %

question 2 ---> option3=100 %

question 3 ---> option4=30 % ---> option5=70 %

....

我尝试了这个查询但不是我的愿望:

[getPollResult]

@poll_form_id int

AS
BEGIN

SELECT a.question_id,a.title,COUNT(*) vote 
FROM tbl_poll_option a 
  JOIN tbl_poll_answer b ON a.Id=b.option_id
  JOIN tbl_poll_question c ON a.question_id=c.Id
WHERE poll_form_id=@poll_form_id 
GROUP BY a.title,a.question_id

END

3 个答案:

答案 0 :(得分:3)

我同意在前端进行计算(如百分比)的建议。

话虽如此,这可能对您有所帮助。
设计限制:这适用于相对较小的数据集,我发现" with()"语法比制作临时表更容易使用,希望我记得清理它们。 (更多关于"与......作为......" sytnax see here)。

以下sql(未经测试)尝试生成两个临时结果集。

counts_by_option - # of votes for each question+option pair
counts_by_question - total # of votes for each question

让我们轻松一点:

counts_by_option

这或多或少是你的开始(实际上更多一点,我想我们以后可能想知道问题和选项,所以我们现在就抓住它们):

with counts_by_option( question_id, question_title, option_id, option_title, vote_cnt )
as (
   SELECT opt.question_id
        , quest.title as question_title
        , opt.id as option_id
        , opt.title as option_title
        , COUNT(*) vote_cnt
   FROM tbl_poll_option opt
   JOIN tbl_poll_answer ans     ON ans.option_id = opt.Id
   JOIN tbl_poll_question quest ON quest.Id = opt.question_id
   WHERE poll_form_id=@poll_form_id
   GROUP BY opt.question_id, quest.title, opt.id, opt.title
)
select * from counts_by_option
order by question_id, option_id

如果可以的话,让我们扩展sql并添加我们的下一个临时结果集......

counts_by_question

现在我们可以使用我们的选项总数来生成每个问题的总票数;我们需要一点来计算实际的%ge。

with counts_by_option( question_id, question_title, option_id, option_title, vote_cnt )
as (
   SELECT opt.question_id
        , quest.title as question_title
        , opt.id as option_id
        , opt.title as option_title
        , COUNT(*) vote_cnt
   FROM tbl_poll_option opt
   JOIN tbl_poll_answer ans     ON ans.option_id = opt.Id
   JOIN tbl_poll_question quest ON quest.Id = opt.question_id
   WHERE poll_form_id=@poll_form_id
   GROUP BY opt.question_id, quest.title, opt.id, opt.title
)
-- select * from counts_by_option order by question_id, option_id
-- (I like to comment out select but leave in place for future testing...)
, counts_by_question( question_id, question_total_votes )
as (
   select question_id, sum(vote_cnt) as question_total_votes 
   from counts_by_option group by question_id
)
select * from counts_by_question order by question_id

如果有效,我们(最终)能够回答有关百分比的原始问题:

百分比示例

with counts_by_option( question_id, question_title, option_id, option_title, vote_cnt )
as (
   SELECT opt.question_id
        , quest.title as question_title
        , opt.id as option_id
        , opt.title as option_title
        , COUNT(*) vote_cnt
   FROM tbl_poll_option opt
   JOIN tbl_poll_answer ans     ON ans.option_id = opt.Id
   JOIN tbl_poll_question quest ON quest.Id = opt.question_id
   WHERE poll_form_id=@poll_form_id
   GROUP BY opt.question_id, quest.title, opt.id, opt.title
)
-- select * from counts_by_option order by question_id, option_id
-- (I like to comment out select but leave in place for future testing...)
, counts_by_question( question_id, question_total_votes )
as (
   select question_id, sum(vote_cnt) as question_total_votes 
   from counts_by_option group by question_id
)
-- select * from counts_by_question order by question_id
select question_id
     , question_title
     , option_id
     , option_title
     , vote_cnt
     , (100.0 * vote_cnt)
       / (select b.question_total_votes
          from counts_by_question b
          where b.question_id = a.question_id
         ) as option_percentage
from counts_by_option a
order by question_id, vote_cnt desc

结果集由 counts_by_option a 驱动。
百分比表达式要求 counts_by_question b 寻求帮助。

让我们关注 option_percentage 的表达式:

(100.0 * vote_cnt)
/ (select b.question_total_votes
   from counts_by_question b
   where b.question_id = a.question_id
)
as option_percentage

这有点复杂(这就是为什么我更喜欢做前端聚合这样的事情)但不是太糟糕......

我们首先将 vote_count 乘以 100.0
然后我们使用当前的OPTION驱动一个命中question_total_values的子查询来查找我们当前问题的总投票数。
注意限定词 a b 这些对于 count_by_question 仅对 a 重点关注我们的子查询非常重要使用这个where子句的当前问题:其中b.question_id = a.question_id (很重要,因为像这样的子查询只能返回一个值,否则它会在执行时出错)。

如果任何问题的总票数为零(例如除以零错误),这将会爆炸。
编辑:构建 counts_by_option 的方式,只会使用带答案的问题(表 tbl_poll_answer ),因此 counts_by_question中的所有值将为非零。

答案 1 :(得分:1)

上述案例的架构

    CREATE TABLE #POLL_QUESTION (QUESTION_ID INT, QUESTION VARCHAR(50))
    INSERT INTO #POLL_QUESTION 
    SELECT 1,'WHAT?'
    UNION ALL
    SELECT 2,'WHEN?'
    UNION ALL
    SELECT 3,'WHY?'
    UNION ALL
    SELECT 4,'WHERE?'


    CREATE TABLE #POLL_OPTION(OPTION_ID INT , QUESTION_ID INT, OPTION_NME VARCHAR(50))
    INSERT INTO #POLL_OPTION
    SELECT 1,1,'A'
    UNION ALL
    SELECT 2,1,'B'
    UNION ALL
    SELECT 3,1,'C'
    UNION ALL
    SELECT 4,2,'A'
    UNION ALL
    SELECT 5,2,'B'
    UNION ALL
    SELECT 6,2,'C'
    UNION ALL
    SELECT 7,3,'A'
    UNION ALL
    SELECT 8,3,'B'
    UNION ALL
    SELECT 9,3,'C'
    UNION ALL
    SELECT 10,4,'A'
    UNION ALL
    SELECT 11,4,'B'
    UNION ALL
    SELECT 12,4,'C'

    CREATE TABLE #POLL_ANSWER(ANSWER_ID INT, OPTION_ID INT)
    INSERT INTO #POLL_ANSWER
    SELECT 1,2
    UNION ALL
    SELECT 2,2
    UNION ALL
    SELECT 3,3
    UNION ALL
    SELECT 4,4
    UNION ALL
    SELECT 5,4
    UNION ALL
    SELECT 6,4
    UNION ALL
    SELECT 7,5
    UNION ALL
    SELECT 8,7
    UNION ALL
    SELECT 9,8
    UNION ALL
    SELECT 10,9
    UNION ALL
    SELECT 11,10
    UNION ALL
    SELECT 12,10

数据的统计

    SELECT Q.QUESTION_ID,Q.QUESTION,O.OPTION_NME,COUNT(O.OPTION_NME)COUNT_OPTION,LEFTQUERY.COUNT_QUESTION, (COUNT(O.OPTION_NME)*100)/LEFTQUERY.COUNT_QUESTION AS PER  FROM #POLL_QUESTION Q
    INNER JOIN #POLL_OPTION O ON Q.QUESTION_ID=O.QUESTION_ID
    INNER JOIN #POLL_ANSWER A ON O.OPTION_ID= A.OPTION_ID
    LEFT JOIN
    (
      SELECT Q.QUESTION_ID,Q.QUESTION, COUNt(O.OPTION_NME)COUNT_QUESTION FROM #POLL_QUESTION Q
    INNER JOIN #POLL_OPTION O ON Q.QUESTION_ID=O.QUESTION_ID
    INNER JOIN #POLL_ANSWER A ON O.OPTION_ID= A.OPTION_ID
    GROUP BY Q.QUESTION_ID,Q.QUESTION

    )AS LEFTQUERY ON  Q.QUESTION_ID= LEFTQUERY.QUESTION_ID
    GROUP BY Q.QUESTION_ID,Q.QUESTION,O.OPTION_NME,
    LEFTQUERY.COUNT_QUESTION 

答案 2 :(得分:1)

select 
  q.title,
  o.title,
  CAST(count(distinct o.id) as float) 
    / (SELECT count(allo.id)
       FROM option allo 
       WHERE q.option_FK = allo.id) 
    * 100.0,
FROM question q
  inner join option o on q.option_FK = o.id
GROUP BY q.id, q.title, q.option_FK, o.id, o.title

(可能需要围绕演员进行一些清理)。

将返回此列表:

question 1, option1, 20.13
question 1, option2, 79.87
question 2, option3, 100
question 3, option4, 30
question 3, option5, 70

理想情况下,它可以用更高级的编程语言进行进一步处理。