SQL多行作为列,不使用PL / SQL

时间:2013-02-28 20:04:11

标签: sql pivot

我有3张桌子

  • questions (q_id, q_text)
  • answers (a_id, a_text, q_id)
  • correct_answers (q_id, a_id)

答案表每个问题最少可以有1个值,最多可以有4个值

我需要一个纯SQL查询(连接或子查询)才能将下表作为结果

result (q_id, q_text, option1, option2, option3, option4, correct)

option1option2option3option4都属于答案表,可以是nullcorrect属于{{1}表}

问题:

correct_answers

数目:

q_id  q_text
2     Capital of Pakistan is
3     Karachi is in africa
5     New dehli is _____ of india

Correct_answer:

a_id  a_text     q_id
1     Lahore     2
2     Islamabad  2
3     Karachi    2
4     Quetta     2
5     True       3
6     False      3
7     Capital    5

查询结果:

q_id  a_id
2     2
3     6
5     7

3 个答案:

答案 0 :(得分:6)

您没有指定RDBMS,但是因为您说PL / SQL我正在猜测Oracle。

根据您的版本,您应该能够使用以下内容 pivot 大多数数据库产品中的数据:

select q_id,
  q_text,
  max(case when rn = 1 then answer end) Option1,
  max(case when rn = 2 then answer end) Option2,
  max(case when rn = 3 then answer end) Option3,
  max(case when rn = 4 then answer end) Option4,
  CorrectAnswer
from
(
  select q.q_id,
    q.q_text,
    a1.a_text Answer,
    a2.a_text CorrectAnswer,
    row_number() over(partition by q.q_id order by a1.a_id) rn
  from questions q
  left join answers a1
    on q.q_id = a1.q_id
  left join Correct_answer ca
    on q.q_id = ca.q_id
  left join answers a2
    on ca.a_id = a2.a_id
)
group by q_id, q_text, CorrectAnswer
order by q_id

请参阅SQL Fiddle with Demo

如果您使用的是Oracle 11g +,则可以使用PIVOT功能:

select q_id,
  q_text,
  Option1, Option2, Option3, Option4,
  CorrectAnswer
from
(
  select q.q_id,
    q.q_text,
    a1.a_text Answer,
    a2.a_text CorrectAnswer,
    row_number() over(partition by q.q_id order by a1.a_id) rn
  from questions q
  left join answers a1
    on q.q_id = a1.q_id
  left join Correct_answer ca
    on q.q_id = ca.q_id
  left join answers a2
    on ca.a_id = a2.a_id
)
pivot
(
  max(answer)
  for rn in ('1' as Option1, '2' as Option2, 
             '3' as Option3, '4' as Option4)
) piv
order by q_id

请参阅SQL Fiddle with Demo

答案 1 :(得分:2)

这个适用于ORACLE,MySQL,MS SQL Server和PostgreSQL

SELECT q_id, 
       q_text,
       (SELECT a_text
          FROM answers a1
         WHERE a1.q_id = q1.q_id
           AND (SELECT count(*) FROM answers a2 WHERE a1.q_id = a2.q_id AND a2.a_id < a1.a_id) = 0) as option1,
       (SELECT a_text
          FROM answers a1
         WHERE a1.q_id = q1.q_id
           AND (SELECT count(*) FROM answers a2 WHERE a1.q_id = a2.q_id AND a2.a_id < a1.a_id) = 1) as option2,
       (SELECT a_text
          FROM answers a1
         WHERE a1.q_id = q1.q_id
           AND (SELECT count(*) FROM answers a2 WHERE a1.q_id = a2.q_id AND a2.a_id < a1.a_id) = 2) as option3,
       (SELECT a_text 
          FROM answers a1
         WHERE a1.q_id = q1.q_id
           AND (SELECT count(*) FROM answers a2 WHERE a1.q_id = a2.q_id AND a2.a_id < a1.a_id) = 3) as option4,
       (SELECT a_text
          FROM answers a1
         WHERE a1.a_id = (select a_id from correct_answers c1 where c1.q_id = q1.q_id)) as correct
  FROM questions q1;

干杯!

答案 2 :(得分:-1)

首先,我要向Position表添加Answers列,其中(q_id, Position)的唯一约束和域约束Position > 0 AND Position <= 4。无论如何,您可能需要Position列;通常最好在行有自然顺序时明确排序,而不是试图通过代理键对它们进行排序,或者只是完全丢弃订购信息。

这使您不再像以下那样查询数据库:

SELECT
        q.qid, q.q_text,
        a1.a_text AS option1, a2.a_text AS option2,
        a3.a_text AS option3, a4.a_text AS option4,
        ca.a_text AS correct
    FROM
        Questions q
        LEFT JOIN Answers a1 ON a1.q_id = q.q_id AND a1.Position = 1
        LEFT JOIN Answers a2 ON a2.q_id = q.q_id AND a2.Position = 2
        LEFT JOIN Answers a3 ON a3.q_id = q.q_id AND a3.Position = 3
        LEFT JOIN Answers a4 ON a4.q_id = q.q_id AND a4.Position = 4
        JOIN Correct_answer qca ON ca.q_id = q.q_id
        JOIN Anwsers ca ON ca.a_id = qca.a_id

你可以侥幸成功,因为你有一定数量的可能答案;更通用的解决方案可能需要动态SQL或应用程序层代码来转动结果集。