使用动态目标列进行查询
Query with dynamic target columns
我正在尝试在 Postgres 中构建一个使用 3 tables 数据的视图。我不确定这是否可行,并且在 google 上搜索了一下,但没有得出任何结论。这就是我正在尝试做的事情:
我有 table 个项目名称 - 假设有 5 个项目:
fruits
id | name
1 | banana
2 | orange
3 | pear
4 | apple
5 | grape
然后我有一个人的名单
people
id | name
1 | Joe Blow
2 | Sally Smith
3 | John Jones
4 | Sam Benny
5 | Nick Stevens
6 | Peter Sandwitch
7 | Sarah Morgan
然后我有第三个 table 链接上面的两个:
people_fruits
person_id | fruit_id
1 | 1
1 | 2
1 | 3
1 | 4
2 | 1
2 | 3
3 | 5
6 | 3
7 | 3
7 | 4
我想做的是能够利用上面的内容动态创建一个视图,该视图将根据水果的内容更改列 table。例如,我希望视图按如下方式显示上述数据:
my_fruity_view
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 |
然后如果我以后要添加水果芒果,下一次查询是 运行(没有修改),它会将其添加为一列:
my_fruity_view
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 | |
这样的查询可以吗?我在堆栈溢出时看到了一些这样的事情——但它似乎是在每列的基础上完成的——但我的数据需要是动态的。
我可以通过编程实现这一点,但我更愿意将其打包到一个视图中以保持整洁。如有任何帮助,我们将不胜感激。
基本上您需要一个 数据透视表 table 或 交叉表 。附加模块 tablefunc
提供了您需要的功能。如果您不熟悉它,请先阅读此内容:
- PostgreSQL Crosstab Query
你的案例的特殊困难:你首先需要一个连接 tables 的查询来产生正确的输入:
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
LEFT [OUTER] JOIN
,不失人无果
在带有 两个 参数的 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 绝对不可能完全动态,这需要在调用时知道结果列。无论哪种方式,您都需要两次往返数据库服务器。您可以让 Postgres 动态构建交叉表查询,然后在下一步中执行它。
带有代码示例的相关答案:
- Dynamic alternative to pivot with CASE and GROUP BY
替代 将是 return 数组或文档类型(json
、xml
、...)包含一个动态元素列表。
我正在尝试在 Postgres 中构建一个使用 3 tables 数据的视图。我不确定这是否可行,并且在 google 上搜索了一下,但没有得出任何结论。这就是我正在尝试做的事情:
我有 table 个项目名称 - 假设有 5 个项目:
fruits
id | name
1 | banana
2 | orange
3 | pear
4 | apple
5 | grape
然后我有一个人的名单
people
id | name
1 | Joe Blow
2 | Sally Smith
3 | John Jones
4 | Sam Benny
5 | Nick Stevens
6 | Peter Sandwitch
7 | Sarah Morgan
然后我有第三个 table 链接上面的两个:
people_fruits
person_id | fruit_id
1 | 1
1 | 2
1 | 3
1 | 4
2 | 1
2 | 3
3 | 5
6 | 3
7 | 3
7 | 4
我想做的是能够利用上面的内容动态创建一个视图,该视图将根据水果的内容更改列 table。例如,我希望视图按如下方式显示上述数据:
my_fruity_view
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 |
然后如果我以后要添加水果芒果,下一次查询是 运行(没有修改),它会将其添加为一列:
my_fruity_view
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 | |
这样的查询可以吗?我在堆栈溢出时看到了一些这样的事情——但它似乎是在每列的基础上完成的——但我的数据需要是动态的。
我可以通过编程实现这一点,但我更愿意将其打包到一个视图中以保持整洁。如有任何帮助,我们将不胜感激。
基本上您需要一个 数据透视表 table 或 交叉表 。附加模块 tablefunc
提供了您需要的功能。如果您不熟悉它,请先阅读此内容:
- PostgreSQL Crosstab Query
你的案例的特殊困难:你首先需要一个连接 tables 的查询来产生正确的输入:
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
LEFT [OUTER] JOIN
,不失人无果
在带有 两个 参数的 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 绝对不可能完全动态,这需要在调用时知道结果列。无论哪种方式,您都需要两次往返数据库服务器。您可以让 Postgres 动态构建交叉表查询,然后在下一步中执行它。
带有代码示例的相关答案:
- Dynamic alternative to pivot with CASE and GROUP BY
替代 将是 return 数组或文档类型(json
、xml
、...)包含一个动态元素列表。