Top*_*gio 38 sql postgresql pivot pivot-without-aggregate
我有一个有趣的难题,我认为可以用纯粹的SQL解决.我有类似于以下的表:
responses:
user_id | question_id | body
----------------------------
1 | 1 | Yes
2 | 1 | Yes
1 | 2 | Yes
2 | 2 | No
1 | 3 | No
2 | 3 | No
questions:
id | body
-------------------------
1 | Do you like apples?
2 | Do you like oranges?
3 | Do you like carrots?
Run Code Online (Sandbox Code Playgroud)
我想得到以下输出
user_id | Do you like apples? | Do you like oranges? | Do you like carrots?
---------------------------------------------------------------------------
1 | Yes | Yes | No
2 | Yes | No | No
Run Code Online (Sandbox Code Playgroud)
我不知道会有多少问题,而且它们是动态的,所以我不能只为每个问题编码.我正在使用PostgreSQL,我相信这称为转置,但我似乎无法找到任何说明在SQL中执行此操作的标准方法.我记得在大学期间在我的数据库课上做这个,但它是在MySQL中,老实说我不记得我们是怎么做到的.
我假设它将是连接和GROUP BY
声明的组合,但我甚至无法弄清楚如何开始.
有人知道怎么做吗?非常感谢!
编辑1:我发现了一些关于使用交叉表的信息,这似乎是我想要的,但我无法理解它.更好的文章的链接将不胜感激!
OMG*_*ies 49
使用:
SELECT r.user_id,
MAX(CASE WHEN r.question_id = 1 THEN r.body ELSE NULL END) AS "Do you like apples?",
MAX(CASE WHEN r.question_id = 2 THEN r.body ELSE NULL END) AS "Do you like oranges?",
MAX(CASE WHEN r.question_id = 3 THEN r.body ELSE NULL END) AS "Do you like carrots?"
FROM RESPONSES r
JOIN QUESTIONS q ON q.id = r.question_id
GROUP BY r.user_id
Run Code Online (Sandbox Code Playgroud)
这是一个标准的数据透视查询,因为您将数据从行"旋转"到列数据.
Han*_*olm 12
我实现了一个真正的动态函数来处理这个问题,而无需硬编码任何特定类的答案或使用外部模块/扩展.它还可以完全控制列排序,并支持多个键和类/属性列.
你可以在这里找到它:https://github.com/jumpstarter-io/colpivot
解决此特定问题的示例:
begin;
create temporary table responses (
user_id integer,
question_id integer,
body text
) on commit drop;
create temporary table questions (
id integer,
body text
) on commit drop;
insert into responses values (1,1,'Yes'), (2,1,'Yes'), (1,2,'Yes'), (2,2,'No'), (1,3,'No'), (2,3,'No');
insert into questions values (1, 'Do you like apples?'), (2, 'Do you like oranges?'), (3, 'Do you like carrots?');
select colpivot('_output', $$
select r.user_id, q.body q, r.body a from responses r
join questions q on q.id = r.question_id
$$, array['user_id'], array['q'], '#.a', null);
select * from _output;
rollback;
Run Code Online (Sandbox Code Playgroud)
这输出:
user_id | 'Do you like apples?' | 'Do you like carrots?' | 'Do you like oranges?'
---------+-----------------------+------------------------+------------------------
1 | Yes | No | Yes
2 | Yes | No | No
Run Code Online (Sandbox Code Playgroud)
您可以通过这种方式使用交叉表功能解决此示例
drop table if exists responses;
create table responses (
user_id integer,
question_id integer,
body text
);
drop table if exists questions;
create table questions (
id integer,
body text
);
insert into responses values (1,1,'Yes'), (2,1,'Yes'), (1,2,'Yes'), (2,2,'No'), (1,3,'No'), (2,3,'No');
insert into questions values (1, 'Do you like apples?'), (2, 'Do you like oranges?'), (3, 'Do you like carrots?');
select * from crosstab('select responses.user_id, questions.body, responses.body from responses, questions where questions.id = responses.question_id order by user_id') as ct(userid integer, "Do you like apples?" text, "Do you like oranges?" text, "Do you like carrots?" text);
Run Code Online (Sandbox Code Playgroud)
首先,您必须安装tablefunc扩展.从9.1版本开始,您可以使用create extension来实现:
CREATE EXTENSION tablefunc;
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
48491 次 |
最近记录: |