PostgreSQL 交叉表查询
如何在 PostgreSQL 中创建交叉表查询?例如,我有下表:
Section Status Count
A Active 1
A Inactive 2
B Active 4
B Inactive 5
我希望查询返回以下交叉表:
Section Active Inactive
A 1 2
B 4 5
How do I create crosstab queries in PostgreSQL? For example I have the following table:
Section Status Count
A Active 1
A Inactive 2
B Active 4
B Inactive 5
I would like the query to return the following crosstab:
Section Active Inactive
A 1 2
B 4 5
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
Crosstab
功能可在tablefunc
扩展下使用。您必须为数据库创建一次此扩展。创建扩展
tablefunc
;您可以使用以下代码使用交叉表创建数据透视表:
Crosstab
function is available under thetablefunc
extension. You'll have to create this extension one time for the database.CREATE EXTENSION
tablefunc
;You can use the below code to create pivot table using cross tab:
安装附加模块
tablefunc
每个数据库一次,提供函数crosstab()
。从 Postgres 9.1 开始,您可以使用CREATE EXTENSION
为此:改进的测试用例
简单形式 - 不适合缺少属性
crosstab(text)
与 1 输入参数:返回:
C
的不正确结果:第一列填充了值7
。有时,这种行为是可取的,但不适合此用例。安全表单
带有 2 输入参数的
crosstab(text, text)
:返回:注意
C.
第二个参数可以是任何查询,每个属性返回一个行,与末尾的列定义的顺序相匹配。通常您会想要从基础表中查询不同的属性,如下所示:
手册中有说明。
由于无论如何您都必须拼写出列定义列表中的所有列(预定义的
crosstabN()
变体除外),因此提供简短的说明通常会更有效在VALUES
表达式中列出,如演示:或者(不在手册中):
我使用了 美元报价使报价更容易。
您甚至可以使用
crosstab(text, text)
输出具有不同数据类型的列 - 只要值的文本表示形式即可列是目标类型的有效输入。这样,您可能会拥有不同类型的属性,并为各个属性输出text
、date
、numeric
等。 章节末尾有一个代码示例手册中的crosstab(text, text)
。db<>fiddle 此处
过多输入行的影响
多余的输入行的处理方式不同 - 相同(“row_name”,“category”)组合的重复行 - 上例中的
(section, status)
。1 个参数表单从左到右填写可用值列。多余的值将被丢弃。
较早的输入行获胜。
2 参数形式将每个输入值分配给其专用列,覆盖任何以前的分配。
稍后输入的行获胜。
通常,您一开始就没有重复项。但如果您这样做,请根据您的要求仔细调整排序顺序 - 并记录发生的情况。
或者如果您不在乎的话,可以快速获得任意结果。只要注意一下效果就可以了。
高级示例
使用 Tablefunc 对多个列进行透视 -还演示了提到的“额外列”
透视的动态替代方案CASE 和 GROUP BY
\crosstabview
在 psqlPostgres 9.6 中将此元命令添加到其默认交互式终端 psql。您可以运行用作第一个
crosstab()
参数的查询,并将其提供给\crosstabview
(立即或在下一步中)。 Like:与上面类似的结果,但它是客户端独有的表示功能。输入行的处理方式略有不同,因此不需要
ORDER BY
。\crosstabview 在手册中。
该页面底部有更多代码示例。
Daniel Vérité(psql 功能的作者)在 dba.SE 上的相关答案:
Install the additional module
tablefunc
once per database, which provides the functioncrosstab()
. Since Postgres 9.1 you can useCREATE EXTENSION
for that:Improved test case
Simple form - not fit for missing attributes
crosstab(text)
with 1 input parameter:Returns:
C
: the value7
is filled in for the first column. Sometimes, this behavior is desirable, but not for this use case.Safe form
crosstab(text, text)
with 2 input parameters:Returns:
Note the correct result for
C
.The second parameter can be any query that returns one row per attribute matching the order of the column definition at the end. Often you will want to query distinct attributes from the underlying table like this:
That's in the manual.
Since you have to spell out all columns in a column definition list anyway (except for pre-defined
crosstabN()
variants), it is typically more efficient to provide a short list in aVALUES
expression like demonstrated:Or (not in the manual):
I used dollar quoting to make quoting easier.
You can even output columns with different data types with
crosstab(text, text)
- as long as the text representation of the value column is valid input for the target type. This way you might have attributes of different kind and outputtext
,date
,numeric
etc. for respective attributes. There is a code example at the end of the chaptercrosstab(text, text)
in the manual.db<>fiddle here
Effect of excess input rows
Excess input rows are handled differently - duplicate rows for the same ("row_name", "category") combination -
(section, status)
in the above example.The 1-parameter form fills in available value columns from left to right. Excess values are discarded.
Earlier input rows win.
The 2-parameter form assigns each input value to its dedicated column, overwriting any previous assignment.
Later input rows win.
Typically, you don't have duplicates to begin with. But if you do, carefully adjust the sort order to your requirements - and document what's happening.
Or get fast arbitrary results if you don't care. Just be aware of the effect.
Advanced examples
Pivot on Multiple Columns using Tablefunc - also demonstrating mentioned "extra columns"
Dynamic alternative to pivot with CASE and GROUP BY
\crosstabview
in psqlPostgres 9.6 added this meta-command to its default interactive terminal psql. You can run the query you would use as first
crosstab()
parameter and feed it to\crosstabview
(immediately or in the next step). Like:Similar result as above, but it's a representation feature on the client side exclusively. Input rows are treated slightly differently, hence
ORDER BY
is not required. Details for\crosstabview
in the manual. There are more code examples at the bottom of that page.Related answer on dba.SE by Daniel Vérité (the author of the psql feature):
您可以使用 附加的
crosstab()
函数模块tablefunc
- 您必须为每个数据库安装一次。从 PostgreSQL 9.1 开始,您可以使用CREATE EXTENSION
< /a> 为此:在你的情况下,我相信它看起来像这样:
DB Fiddle here:
CREATE EXTENSION tablefunc;
,您会收到此错误: https://dbfiddle.uk/j8W1CMvIYou can use the
crosstab()
function of the additional moduletablefunc
- which you have to install once per database. Since PostgreSQL 9.1 you can useCREATE EXTENSION
for that:In your case, I believe it would look something like this:
DB Fiddle here:
CREATE EXTENSION tablefunc;
you get this error: https://dbfiddle.uk/j8W1CMvIJSON聚合的解决方案:
Solution with JSON aggregation:
抱歉,这并不完整,因为我无法在这里测试它,但它可能会让您朝着正确的方向前进。我正在翻译我使用的类似查询的内容:
我正在使用的代码是:
它将返回 typeID、最高出价和最低要价以及两者之间的差异(正差异意味着某物的购买价格可能低于其出售价格)。
Sorry this isn't complete because I can't test it here, but it may get you off in the right direction. I'm translating from something I use that makes a similar query:
The code I'm working from is:
which will return a typeID, the highest price bid and the lowest price asked and the difference between the two (a positive difference would mean something could be bought for less than it can be sold).
我设计了一种不同的动态方法,它采用动态记录。类型(临时表,通过匿名过程构建)& JSON。这对于无法安装 tablefunc/crosstab 扩展但仍可以创建临时表或运行的最终用户可能很有用。过程的。
该示例假设所有 xtab 列都是相同类型 (INTEGER),但列数是数据驱动的 &可变参数。也就是说,JSON 聚合函数确实允许混合数据类型,因此通过使用嵌入式复合(混合)类型有创新的潜力。
如果您想静态定义rec,则其真正的内容可以减少到一步。 JSON 记录集函数内的类型(通过发出复合类型的嵌套 SELECT)。
dbfiddle.uk
https://dbfiddle.uk/N1EzugHk
There's a different dynamic method that I've devised, one that employs a dynamic rec. type (a temp table, built via an anonymous procedure) & JSON. This may be useful for an end-user who can't install the tablefunc/crosstab extension, but can still create temp tables or run anon. proc's.
The example assumes all the xtab columns are the same type (INTEGER), but the # of columns is data-driven & variadic. That said, JSON aggregate functions do allow for mixed data types, so there's potential for innovation via the use of embedded composite (mixed) types.
The real meat of it can be reduced down to one step if you want to statically define the rec. type inside the JSON recordset function (via nested SELECTs that emit a composite type).
dbfiddle.uk
https://dbfiddle.uk/N1EzugHk