【问题标题】:PostgreSQL - Modify CREATE TABLE syntax in an extensionPostgreSQL - 在扩展中修改 CREATE TABLE 语法
【发布时间】:2016-06-10 03:32:21
【问题描述】:

是否可以编写修改 DDL 语法的 PostgreSQL 扩展?

我正在 PostgreSQL 和 PostGIS 之上创建一个扩展,以支持特定空间数据模型 (OMT-G) 的完整性约束。为此,我想修改 CREATE TABLE 语法,它接受 CONSTRAINTS 的语法:

CONSTRAINT constraint_name CHECK ( expression )

但我想创建自己的语法,如下例所示,然后它将调用我已经编写的函数或触发器。

CREATE TABLE school_district (
      id integer PRIMARY KEY,
      school_name varchar(120)
      geom geometry,

      SPATIAL_CONSTRAINT PLANAR_SUBDIVISION (geom),
      SPATIAL_CONSTRAINT CONTAINS school (geom)**
);

这可能吗?如果有,怎么做?

【问题讨论】:

  • 不,这是不可能的。但是,如果您能提供一个真实示例来说明您真正想要实现的目标,那么可能会有一些替代解决方案。
  • 只需使用CHECK 语法。那应该可以实现您想要的。
  • @Patrick,这实际上是我想要实现的。添加一些语法糖,以方便空间开发人员。例如,上面片段的第二个约束将证明对于添加到表中的每个新 school_district,其边界内的学校(在表学校中)必须存在。
  • @GordonLinoff 但我们的想法是为这个空间数据模型创建一个扩展。所以最好有一个像上面这样的语法。而且约束有点复杂,功能很多,如果可能的话,这将简化使用。
  • 还是不行。如果你想扩展语法,你必须修改源代码并直接在 C 中编写功能。可能不是一个非常可行的想法......如果你有很多重复的约束并希望简化它,请查看domains跨度>

标签: sql postgresql postgis postgresql-9.1 ddl


【解决方案1】:

正如其他人所评论的那样,不可能通过扩展来更改 Postgres 语法。黑客的邮件列表中对此进行了一些讨论,但没有人认为有任何可行的方法可以使 Bison 语法可扩展。

您提出的另一个问题是 CHECK 约束(看起来是您在此处尝试执行的操作)无法安全地引用其他表。

听起来你真正想要的是可扩展的外键支持。这也是社区实际上想要的东西,至少对于数组来说是这样。这个想法是支持类似 int[] 的东西,其中每个元素都应该被视为对另一个表的外键引用。您所描述的是相似的:您想要使用不同的运算符,而不是不同的数据类型。

目前,我认为您能做的最好的事情就是为您的用户提供一个函数,该函数将在表格中放置适当的列和触发器。该列将是学校表的外键。触发器将找到合适的学校并将其主键填充到新列中。 (您可能还希望在学校表上使用 BEFORE DELETE 触发器来处理删除学校的问题。)

您需要外键字段的原因是因为外键触发器使用与普通查询不同的可见性规则运行,因此您无法在用户空间中完全模拟它们。如果您不是那么偏执,您可以只使用一个 AFTER INSERT 触发器来查找学校,如果找不到则抛出错误。

【讨论】:

  • 感谢@Jim。实际上,由于数据是空间的,因此不是外键。两个表之间的关系可以只是空间的。 (检查一个元素在地理上是否在另一个元素的边界内),没有外键。不过谢谢。我会想另一种方法让这些约束更易于使用。
【解决方案2】:

就任何纯 DDL 解决方案而言,最有前途的方法是使用 CREATE TABLE ... CONSTRAINT ... EXCLUDE,它在单个表上运行 GiST,并且仅在边界框上工作的运算符相对有限(例如 &&):

CREATE TABLE polygons (
    geom geometry(Polygon,4326),
    EXCLUDE USING gist (geom WITH &&)
);
INSERT INTO polygons(geom)
VALUES('SRID=4326;POLYGON ((0 0, 0 1, 1 0, 0 0))');

但是,这种冲突(即使几何实际上并不重叠):

INSERT INTO polygons(geom)
VALUES('SRID=4326;POLYGON ((1 1, 1 2, 2 2, 2 1, 1 1))');

错误:冲突的键值违反了排除约束“polygons_geom_excl” DETAIL:密钥(GEOM)=(0103000020E61000000100000005000000000000000000F03F000000000000F03F000000000000F03F0000000000000040000000000000004000000000000000400000000000000040000000000000F03F000000000000F03F000000000000F03F)与现有的键(的geom)=(0103000020E61000000100000004000000000000000000000000000000000000000000000000000000000000000000F03F000000000000F03F000000000000000000000000000000000000000000000000)冲突 P>


正如@Jim 上面提到的,让一个表在另一个表上构建约束的最佳方法是创建一个好的trigger function,并在两个表上都使用它。它通常用 PL/pgSQL 编写,您可以在其中嵌入有用的消息,例如:

RAISE EXCEPTION 'School % is not located in school district % (it is % away)',
                s.name, d.name, ST_Distance(s.geom, d.geom);

这样,如果您编辑 school_districtschools 表,触发器将检查 UPDATEINSERTDELETE 以查看条件是否仍然有效。

【讨论】:

    猜你喜欢
    • 2015-11-21
    • 1970-01-01
    • 2018-06-06
    • 1970-01-01
    • 1970-01-01
    • 2010-12-04
    • 2017-06-30
    • 1970-01-01
    相关资源
    最近更新 更多