使用更简单的模式会更简单:
- 没有域类型(目的是什么?)
- 在表中添加实际的PK
medium
- 而是使用代理PK(一
serial
列)代替两种域类型上的多列PK和FK。
或者至少对具有相同内容的列使用相同(更简单)的列名:alpha_id
代替m_alphaID
andw_alphaID
等等。
顺便说一句,这里是 按原样 设置的解决方案:
真正的crosstab()
解决方案
您的
crosstab()查询有几个特定的困难:
- 没有任何单一列可以用作 row_name 。
- 多个额外的列。
- 没有 类别 列。
- 没有定义值的顺序(因此我改用任意顺序)。
基础知识( 请先阅读! ):
- PostgreSQL交叉表查询
对于您的特殊情况:
- 使用Tablefunc在多个列上枢轴
解决方案:
SELECt alphaid, numid, name_of_work, material_1, material_2, material_3FROM crosstab( 'SELECt rn, w.alphaid, w.numid, w.name_of_work , row_number() OVER (PARTITION BY rn) AS mat_nr -- order undefined! , m_title AS Material_used FROM ( SELECt w_alphaID AS alphaid, w_numID AS numid, w_title AS name_of_work, row_number() OVER (ORDER BY w_alphaID, w_numID) AS rn FROM works ) w JOIN medium m ON w.alphaid = m.m_alphaID AND w.numid = m.m_numID ORDER BY rn, mat_nr' , 'VALUES (1), (2), (3)' -- add more ...) AS ct ( rn bigint, alphaid text, numid int, name_of_work text , material_1 text, material_2 text, material_3 text -- add more ... );
标准SQL的可怜人的交叉表
如果无法安装附加模块tablefunc或顶级性能并不重要,则此简单查询将执行相同的操作,但速度较慢:
SELECt w_alphaid AS alphaid, w_numid AS numid, w_title AS name_of_work , arr[1] AS material_used_1 , arr[2] AS material_used_2 , arr[3] AS material_used_3 -- add more?FROM works wLEFT JOIN ( SELECt m_alphaid, m_numid, array_agg(m_title::text) AS arr FROM medium GROUP BY m_alphaid, m_numid ) m ON w.w_alphaid = m.m_alphaid AND w.w_numid = m.m_numid;
强制转换为
text
(或varchar
…)是必需的,因为您的自定义域没有预定义的数组类型。或者,您可以定义缺少的数组类型。与上面的一个细微差别:使用
LEFT JOIN
此处而不是仅JOIN
保留works
完全 没有 相关材料的行medium
。由于返回了整个表,因此在加入行
medium
之前 汇总行比较便宜。对于较小的选择,首先加入 然后进行汇总 可能会比较便宜。



