简体   繁体   English

转置sql结果,使一列进入多列

[英]Transposing an sql result so that one column goes onto multiple columns

I'm trying to get data out of a table for a survey in a particular format. 我正试图从一个表格中获取特定格式的调查数据。 However all my attempts seems to hand the DB because of too many joins/too heavy on the DB. 但是我的所有尝试似乎都是因为DB上的连接太多/太重而无法提交数据库。

My data looks like this: 我的数据如下:

id, user, question_id, answer_id, 
1,   1,   1,           1
3,   1,   3,           15
4,   2,   1,           2
5,   2,   2,           12
6,   2,   3,           20

There are roughly 250,000 rows and each user has about 30 rows. 大约有250,000行,每个用户大约有30行。 I want the result to look like: 我希望结果看起来像:

user0, q1, q2,   q3 
1,     1,  NULL, 15
2,     2,  12,   20 

So that each user has one row in the result, each with a separate column for each answer. 这样每个用户在结果中都有一行,每行都有一个单独的列用于每个答案。

I'm using Postgres but answers in any SQL language would be appreciated as I could translate to Postgres. 我正在使用Postgres,但任何SQL语言的答案都会受到赞赏,因为我可以翻译成Postgres。

EDIT: I also need to be able to deal with users not answering questions, ie in the example above q2 for user 1. 编辑:我还需要能够处理不回答问题的用户,即上面的示例q2用户1。

Consider the following demo: 请考虑以下演示:

CREATE TEMP TABLE qa (id int, usr int, question_id int, answer_id int);
INSERT INTO qa VALUES
 (1,1,1,1)
,(2,1,2,9)
,(3,1,3,15)
,(4,2,1,2)
,(5,2,2,12)
,(6,2,3,20);

SELECT *
FROM   crosstab('
    SELECT usr::text
          ,question_id
          ,answer_id
    FROM qa
    ORDER BY 1,2')
 AS ct (
     usr text
    ,q1 int
    ,q2 int
    ,q3 int);

Result: 结果:

 usr | q1 | q2 | q3
-----+----+----+----
 1   |  1 |  9 | 15
 2   |  2 | 12 | 20
(2 rows)

user is a reserved word . user保留字 Don't use it as column name! 不要将它用作列名! I renamed it to usr . 我把它改名为usr

You need to install the additional module tablefunc which provides the function crosstab() . 您需要安装附加模块tablefunc ,它提供了函数crosstab() Note that this operation is strictly per database . 请注意,此操作严格按照数据库进行 In PostgreSQL 9.1 you can simply: 在PostgreSQL 9.1中,您可以简单地:

CREATE EXTENSION tablefunc;

For older version you would execute a shell-script supplied in your contrib directory. 对于旧版本,您将执行contrib目录中提供的shell脚本。 In Debian, for PostgreSQL 8.4 , that would be: 在Debian中,对于PostgreSQL 8.4 ,它将是:

psql mydb -f /usr/share/postgresql/8.4/contrib/tablefunc.sql

Erwins answer is good, until missing answer for a user shows up. Erwins的答案很好,直到缺少用户的答案出现。 I'm going to make an assumption on you....you have a users table that has one row per user and you have a questions table that has one row per questions. 我将对你做出一个假设....你有一个用户表,每个用户有一行,你有一个问题表,每个问题有一行。

select usr, question_id
from users u inner join questions q on 1=1
order by 1,

This statement will create a row for every user/question, and be in the same order. 此语句将为每个用户/问题创建一行,并且顺序相同。 Turn it into a subquery and left join it to your data... 将其转换为子查询,然后将其连接到您的数据......

select usr,question_id,qa.answer_id
from
(select usr, question_id
from users u inner join questions q on 1=1
)a
left join qa on qa.usr = a.usr and qa.question_id = a.usr
order by 1,2

Plug that into Erwins crosstab statement and give him credit for the answer :P 将其插入Erwins交叉表声明并给出他的答案:P

I implemented a truly dynamic function to handle this problem without having to hard code any specific number of questions or use external modules/extensions. 我实现了一个真正的动态函数来处理这个问题,而无需硬编码任何特定数量的问题或使用外部模块/扩展。 It also much simpler to use than crosstab() . 它比crosstab()更简单易用。

You can find it here: https://github.com/jumpstarter-io/colpivot 你可以在这里找到它: https//github.com/jumpstarter-io/colpivot

Example that solves this particular problem: 解决此特定问题的示例:

begin;

create temp table qa (id int, usr int, question_id int, answer_id int);
insert into qa values
 (1,1,1,1)
,(2,1,2,9)
,(3,1,3,15)
,(4,2,1,2)
,(5,2,2,12)
,(6,2,3,20);

select colpivot('_output', $$
    select usr, ('q' || question_id::text) question_id, answer_id from qa
$$, array['usr'], array['question_id'], '#.answer_id', null);

select * from _output;

rollback;

Result: 结果:

 usr | 'q1' | 'q2' | 'q3' 
-----+------+------+------
   1 |    1 |    9 |   15
   2 |    2 |   12 |   20
(2 rows)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM