交叉表查询提供了意外的结果

时间:2018-12-21 13:38:29

标签: sql postgresql crosstab

我对PostgreSQL的tablefunc扩展中的crosstab()函数有些困惑。问题是我不希望使用标准的 Name-Category-Value 方案,而是要使用 Name-Name-Name-One-more attribute-Category-Value 这样的名称。似乎没有什么问题,但是不久我就意识到,使用我的数据库方案并没有我想的那么容易。

背景:我要使用3个表:用户 UserEvents QuestionaryAnswers

  1. “用户”表包含人员
  2. UserEvents包含此人发生的事件(FK引用了Users)
  3. 和QuestionaryAnswers,其中包含通过FK引用UserEventId的问题的答案。

因此,表如下所示:

create table "Users"("Id" int, "AttrId" int, "GroupId" int);
create table "UserEvents"("Id" int, "UserId" int, "Status" varchar(20), "EventId" int);
create table "QuestionaryAnswers"("UserEventId" int, "QuestionaryItemId" int, "AnswerItemId" int);

用户:

INSERT INTO "public"."Users"("Id", "AttrId", "GroupId") 
VALUES (1, 1, 12587), (2, 1, 11092);

UserEvents:

INSERT INTO "public"."UserEvents"("Id", "UserId", "Status", "EventId") 
VALUES (142, 1, 'Checked', 2), (143, 1, 'Created', 1), (144, 2, 'Done', 2);

问题解答:

INSERT INTO "public"."QuestionaryAnswers"("UserEventId", "QuestionaryItemId", "AnswerItemId") 
VALUES ('142', 1, 2),
('142', 4, 16),
('142', 5, 25),
('143', 12, 99);
('144', 12, 100);

好吧,那就是出现问题的地方。这是我现在的交叉表查询:

SELECT *
FROM crosstab(' SELECT "UserEvents"."UserId", "QuestionaryAnswers"."UserEventId", "Users"."AttrId", "Users"."GroupId", "QuestionaryAnswers"."QuestionaryItemId", "AnswerItems"."Name"
 FROM "QuestionaryAnswers"
    LEFT JOIN "AnswerItems" ON "QuestionaryAnswers"."AnswerItemId" = "AnswerItems"."Id" 
    LEFT JOIN "UserEvent" ON "QuestionaryAnswers"."UserEventId" = "UserEvents"."Id" 
    LEFT JOIN "Users" ON "UserEvents"."UserId" = "Users"."Id"
    ORDER BY 1, 2'::text, 
'SELECT 1 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 10 UNION SELECT 11 UNION SELECT 12 UNION SELECT 13 UNION SELECT 14 UNION SELECT 15 UNION SELECT 16 UNION SELECT 17 UNION SELECT 18 UNION SELECT 20 UNION SELECT 21 ORDER BY 1'::text) 
crosstab("UserId" integer, "UserEventId" uuid,
"AttrId" integer, "GroupId" integer,
"Question1" text, "2" text, "3" text, "4" text,
"5" text, "6" text, "7" text, "8" text, "9" text,
"10" text, "11" text, "12" text, "13" text, "14" text,
"15" text, "16" text, "17" text, "18" text, "19" text)

这里看起来似乎很简单,只是有一个小细节-类别\列\问题链接到不同的 UserEventId ,因此基本上UserEventId是随机选择的(通过ORDER子句),并且由于 UserEvents 表中的Status属性也将被随机选择。我想看到的是分别由 EventId 派生的UserEventId和Status字段,因此会有 UserEventId_1 UserEventId_2 ID,并且可能已链接字段,例如 Status_1 Status_2 ,如下所示:

UserId | UserEventId_EventId1 | UserEventId_EventId2 | AttrId | GroupId | Question1 | Question3 | Question4 | Question5 | Question12
-------+----------------------+----------------------+--------+---------+-----------+-----------+-----------+-----------+-----------
     1 |                  143 |                  142 |      1 |   12587 |           |           |        16 |        25 |         99
     2 |                      |                  144 |      1 |   11092 |           |           |           |           |        144

所以问题是:

  1. 如何根据外键值创建“类别”交叉表列?我无法弄清楚,可能是因为事件和问题是类别的不同“堆栈”。
  2. 整个想法有点错误-交叉表并不是要以我想要的格式显示数据,所以我会达到目标。我需要一个表格来运行简单的比较查询“有多少人回答了这样的问题1,而回答了这样的问题2”,但是我还需要在“ UserEvents” Status 字段和“用户” GroupId 字段,因此我需要在表内添加EventID或Status。我是否缺少一些机会来简化此工作,或者缺少一些在交叉表中显示此数据的能力? PS我正在使用PostgreSQL 11.1

1 个答案:

答案 0 :(得分:0)

到目前为止,无需交叉表调用就可以实现您所描述的内容:

select u1."Id" as "UserId", u1."GroupId", e1."Status", 
    q1."QuestionaryItemId", q1."AnswerItemId", count(*)
from "Users" u1
left join "UserEvents" e1
on u1."Id" = e1."UserId"
left join "QuestionaryAnswers" q1
on q1."UserEventId"=e1."Id"
group by 1,2,3,4,5

您可以查看结果here