Postgresql 具有动态目标列的查询

Postgresql 具有动态目标列的查询,postgresql,join,many-to-many,pivot,crosstab,Postgresql,Join,Many To Many,Pivot,Crosstab,我试图在Postgres中构建一个视图,该视图使用3个表的数据。我不确定这是否可能,我在谷歌上搜索了一下,但没有找到任何结论。这就是我试图做的: 我有一个项目名称表-假设有5个项目: 水果 id | name 1 | banana 2 | orange 3 | pear 4 | apple 5 | grape person_id | fruit_id 1 | 1 1 | 2 1 | 3 1 | 4 2 |

我试图在Postgres中构建一个视图,该视图使用3个表的数据。我不确定这是否可能,我在谷歌上搜索了一下,但没有找到任何结论。这就是我试图做的:

我有一个项目名称表-假设有5个项目:

水果

id | name
1  | banana
2  | orange
3  | pear
4  | apple
5  | grape
person_id | fruit_id
1         | 1
1         | 2
1         | 3
1         | 4
2         | 1
2         | 3
3         | 5
6         | 3
7         | 3
7         | 4
然后我有一份名单

id  |  name
1   |  Joe Blow
2   |  Sally Smith
3   |  John Jones
4   |  Sam Benny
5   |  Nick Stevens
6   |  Peter Sandwitch
7   |  Sarah Morgan
然后,我有第三个表链接上述两个:

people\u fruits

id | name
1  | banana
2  | orange
3  | pear
4  | apple
5  | grape
person_id | fruit_id
1         | 1
1         | 2
1         | 3
1         | 4
2         | 1
2         | 3
3         | 5
6         | 3
7         | 3
7         | 4
我试图做的是能够利用上面的方法动态创建一个视图,该视图将根据水果表的内容更改列。例如,我希望视图显示上述数据,如下所示:

我的水果视图

name            | bananna | orange | pear | apple | grape
Joe Blow        | X       | X      | X    | X     |
Sally Smith     | X       |        | X    |       |
John Jones      |         |        |      |       | X
Sam Benny       |         |        |      |       |
Nick Stevens    |         |        |      |       |
Peter Sandwitch |         |        | X    |       |
Sarah Morgan    |         |        | X    | X     |
name            | bananna | orange | pear | apple | grape | mango
Joe Blow        | X       | X      | X    | X     |       |
Sally Smith     | X       |        | X    |       |       |
John Jones      |         |        |      |       | X     |
Sam Benny       |         |        |      |       |       |
Nick Stevens    |         |        |      |       |       |
Peter Sandwitch |         |        | X    |       |       |
Sarah Morgan    |         |        | X    | X     |       |
然后,如果我以后再添加水果芒果,下次运行查询时(无需修改),它会将其添加为一列:

我的水果视图

name            | bananna | orange | pear | apple | grape
Joe Blow        | X       | X      | X    | X     |
Sally Smith     | X       |        | X    |       |
John Jones      |         |        |      |       | X
Sam Benny       |         |        |      |       |
Nick Stevens    |         |        |      |       |
Peter Sandwitch |         |        | X    |       |
Sarah Morgan    |         |        | X    | X     |
name            | bananna | orange | pear | apple | grape | mango
Joe Blow        | X       | X      | X    | X     |       |
Sally Smith     | X       |        | X    |       |       |
John Jones      |         |        |      |       | X     |
Sam Benny       |         |        |      |       |       |
Nick Stevens    |         |        |      |       |       |
Peter Sandwitch |         |        | X    |       |       |
Sarah Morgan    |         |        | X    | X     |       |
这样的质疑可能吗?我在堆栈溢出上看到了一些类似的情况——但它似乎是在每列的基础上完成的——但我的数据需要是动态的


我可以通过编程实现这一点,但我更愿意将其打包成一个视图,以保持整洁。在此方面的任何帮助都将不胜感激。

基本上,您需要一个透视表或交叉列表。附加模块
tablefunc
提供您需要的功能。如果您不熟悉,请先阅读以下内容:

案例的特殊困难在于:首先需要一个连接表的查询来生成正确的输入:

SELECT p.name, f.name, text 'x' AS marker -- required, logically redundant column
FROM   people             p
LEFT   JOIN people_fruits pf ON pf.person_id = p.id  -- LEFT JOIN !
LEFT   JOIN fruits        f  ON f.id = pf.fruit_id
ORDER  BY p.id, f.id;  -- seems to be the desired sort order
左[OUTER]加入
,这样你就不会失去没有果实的人

crosstab()
函数中使用它,使用如下两个参数:

SELECT * FROM crosstab(
    $$SELECT p.name, f.name, text 'x'
      FROM   people             p
      LEFT   JOIN people_fruits pf ON pf.person_id = p.id
      LEFT   JOIN fruits        f  ON f.id = pf.fruit_id
      ORDER  BY p.id$$   
   ,$$VALUES ('bananna'), ('orange'), ('pear'), ('apple'), ('grape')$$)
AS ct (name text, bananna text, orange text, pear text, apple text, grape text);
目标列列表中的水果顺序必须与第二个参数中的水果顺序相匹配(在您的情况下,按
id
排序)

缺少的水果将获取一个
NULL

然而,这还不是动态的。SQL完全动态是不可能的,它要求在调用时知道结果列。无论如何,您需要两次往返到DB服务器。您可以让Postgres动态构建交叉表查询,然后在下一步执行它

与代码示例相关的答案:


另一种方法是返回一个数组或文档类型(
json
xml
,…),其中包含一个动态元素列表。

与其为格式问题道歉,不如直接正确格式化。友好的格式说明如下:您的问题看起来没那么糟糕,我们看到了更糟的情况。谢谢你,注意到了!非常感谢这个欧文-这是简单和信息。我可以看到,按照您的说法,要么进行“两次往返”,要么返回一些json或xml,这将是一种方式。我将尝试通过将列名返回到我的应用程序来实现这一点,按照上面的格式将它们解析为字段名,并使用包含解析的列名运行新查询。好的-我尝试了一下,并提出了一个初始格式查询,它按照上面的示例构建了两组列名:
select string_agg(concat(“(”,name,“)”),“,”order by name)作为fruits union的fruits_列,选择concat('name text','string_agg(concat(name,'text'),','order by name))作为fruits的fruits_列
,然后将其传递到我的应用程序,并用于根据上面的答案构建完整的查询。从那里我可以得到我想要的确切格式!!