VIEW定义中的“错误:列...指定了多次”

时间:2016-08-05 17:38:21

标签: sql postgresql postgresql-9.4 sql-view set-returning-functions

这是earlier one的后续问题。我有一个存储函数f1,它接受​​两个参数返回一个包含5列的表;现在返回的值是常量,稍后它们将从参数计算。

我还有一个表t1,其中有两列在类型上与f1的参数相对应。

我现在要定义一个视图v1,其中包含f1t1中存储的所有参数对返回的所有行的并集。对于给定的示例值,结果应为:

+---+---+---+---+---+---+---+
| 2 | 3 | a | b | 1 | c | d |
+---+---+---+---+---+---+---+
| 4 | 5 | a | b | 1 | c | d |
+---+---+---+---+---+---+---+

如果前两列被剥离,那也没关系。请注意,f1可以为某些参数值返回多行。

我已经尝试了以下语句,但它给了我这个错误消息:

ERROR: column "c4" specified more than once
CREATE VIEW v1 (c1, c2, c3, c4, c5)
AS SELECT * FROM
  (SELECT c1, c2 FROM t1) AS x,
  f1 (x.c1, x.c2);

我做错了什么?

以下是设置示例的前述陈述:

CREATE OR REPLACE FUNCTION f1 (a1 INTEGER, a2 INTEGER)
RETURNS TABLE (c1 VARCHAR(20), c2 VARCHAR(20), c3 INTEGER, c4 VARCHAR(20), c5 VARCHAR(128))
AS $$
SELECT 'a'::VARCHAR(20), 'b'::VARCHAR(20), 1::INTEGER, 'c'::VARCHAR(20), 'd'::VARCHAR(128);
$$ LANGUAGE SQL;

DROP TABLE IF EXISTS t1;
CREATE TABLE t1 (c1 INTEGER, c2 INTEGER);
INSERT INTO t1 (c1, c2)
VALUES (2,3), (4,5);

DROP VIEW IF EXISTS v1;

1 个答案:

答案 0 :(得分:1)

我建议在LATERAL查询中加入SELECT

CREATE VIEW v1 AS
SELECT f.*
FROM   t1
     , f1 (t1.c1, t1.c2) AS f;  -- implicit CROSS JOIN LATERAL

由于函数定义中定义的列名称已经匹配了您想要的列名称,因此您也可以从视图定义中删除列名称。

无论如何,创建视图都适用于早期绑定。意思是,只有在创建时选择的列才会包含在视图中。如果您稍后更改函数定义以返回其他列,则视图中包含 。 (如果删除或重命名列,则会破坏视图。)

可以还在f1(..)列表中包含设置返回函数SELECT几乎效果相同。差异:

  • SELECT列表中的设置返回函数违反了SQL标准,并且有些人不赞同。也不能移植到其他一些RDBMS。由于Postgres在Postgres 9.3中引入了(标准SQL)LATERAL,因此通常更可取。

  • SELECT列表中的集合返回函数(实际上是相关子查询)相当于LEFT JOIN LATERAL ... ON true,即保留t1的所有行,即使函数不返回任何行。上面的CROSS JOIN LATERAL 删除了<{1}}不返回行的行。

  • 可以分解从f1()函数返回的明确定义的行类型,但是可以对返回类型中的每一列重复计算该函数,而不是一次仅

相关和更多细节: