我正在尝试从特定格式的调查表中获取数据。但是我的所有尝试似乎都是因为DB上的连接太多/太重而无法提交数据库。
我的数据如下:
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
大约有250,000行,每个用户大约有30行。我希望结果看起来像:
user0, q1, q2, q3
1, 1, NULL, 15
2, 2, 12, 20
这样每个用户在结果中都有一行,每行都有一个单独的列用于每个答案。
我正在使用Postgres,但任何SQL语言的答案都会受到赞赏,因为我可以翻译成Postgres。
编辑:我还需要能够处理不回答问题的用户,即在上面的示例q2中,用户1。
答案 0 :(得分:6)
考虑以下演示:
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);
结果:
usr | q1 | q2 | q3
-----+----+----+----
1 | 1 | 9 | 15
2 | 2 | 12 | 20
(2 rows)
user
是reserved word。不要将它用作列名!我将其重命名为usr
。
您需要安装提供功能crosstab()
的附加模块tablefunc。请注意,此操作严格按每个数据库。
在PostgreSQL 9.1 中,您可以简单地说:
CREATE EXTENSION tablefunc;
对于旧版本,您将执行contrib
目录中提供的shell脚本。在Debian中,对于PostgreSQL 8.4 ,那将是:
psql mydb -f /usr/share/postgresql/8.4/contrib/tablefunc.sql
答案 1 :(得分:3)
Erwins的回答很好,直到用户的错过答案显示出来。我将对你做出假设....你有一个用户表,每个用户有一行,你有一个问题表,每个问题有一行。
select usr, question_id
from users u inner join questions q on 1=1
order by 1,
此语句将为每个用户/问题创建一行,并且顺序相同。将其转换为子查询,然后将其连接到您的数据......
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
将其插入Erwins交叉表声明中,并将其归功于答案:P
答案 2 :(得分:1)
我实现了一个真正的动态函数来处理这个问题,而无需硬编码任何特定数量的问题或使用外部模块/扩展。它的使用也比crosstab()
简单得多。
您可以在此处找到它:https://github.com/jumpstarter-io/colpivot
解决此特定问题的示例:
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;
结果:
usr | 'q1' | 'q2' | 'q3'
-----+------+------+------
1 | 1 | 9 | 15
2 | 2 | 12 | 20
(2 rows)