PostgreSQL:如何实现最小基数?
正如这个问题所回答的:PostgreSQL 中的基数,使用约束。
基数规则定义了允许的关系数量——一对多、多对多等。多对多是使用连接表实现的,一对多是使用外键实现的。
但是如何实现一对一或多(一对一+)关系。这与问:如何在 PostgreSQL 中强制执行最小基数?
一种实际情况是,需要存储个人(例如用户或客户)必须提供的地址(或电话号码)(但可以不止一个)。
编辑:
上述情况是一般问题的特殊情况(基数为一)。一般问题是:如何强制任意数的基数?
正如由jug回答非空< /em> 如果最小基数为 1,则可以使用外键引用作为解决方法。它还将提供一个附加功能来在众多功能中选择默认值。
但考虑一下板球队与其球队之间关系的另一种情况强>玩家。每支球队必须至少有 11 名球员才能获得团队资格。这里的最小基数是十一 (11)。
类似地,学校中课程和学生之间的关系,每个学生必须注册至少 5 门课程,并且每门课程必须至少有 10 名学生。
As answered in this question: Cardinality in PostgreSQL, cardinality is enfforced using constraints.
Cardinality rules define the allowable counts of the relationships – one-to-many, many-to-many, etc. Many-to-many is achieved using join-tables and one-to-many using FOREIGN KEY.
But how can one implement one-to-one_or_many (one-to-1+) relationship. Which is same as to ask: How can I enforce minimum cardinality in PostgreSQL?
A practical situation would be where one needs to store say address (or telephone number) which MUST be provided (but can be more that one) by the person (say user or customer).
Edit:
The above mentioned situation is a special case (with cardinality one) of a general problem. The general problem being: How to enforce cardinality of arbitrary number?
As answered by jug a non-null FOREIGN KEY reference can be used as a work-around, if minimum-cardinality is one. It will also provide an additional feature to select default among many.
But consider another situation of relationship between team of Cricket and its players. Every team MUST have a MINIMUM of 11 players to qualify as a team. Here the minimum cardinality is eleven (11).
Similary, a relation between a course and a student in a school, where every student MUST enroll in AT-LEAST 5 courses and every course MUST have a MINIMUM of 10 students.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
无法使用 CHECK 约束来指定这一点,因此我认为最好的方法是触发器:
http://www.postgresql.org/docs/9.1/static/sql-createtrigger.html
http://www.postgresql.org/docs/9.1/static/plpgsql -trigger.html
你最终会得到类似的结果(我还没有测试过它或任何东西):
There's no way to specify this using a CHECK constraint, so I think the best approach is a trigger:
http://www.postgresql.org/docs/9.1/static/sql-createtrigger.html
http://www.postgresql.org/docs/9.1/static/plpgsql-trigger.html
You'd end up with something like (I haven't tested it or anything):
仅使用
FOREIGN KEY
约束无法强制执行此类规则。1)一种方法是允许表之间的循环引用(“默认”列,由 jug 建议)。这会导致难以管理的先有鸡还是先有蛋的问题,您必须使用可延迟约束。另外,这个选项在某些 DBMS 中根本不可用。另一个缺点是,对于一支足球队,您必须添加 11 个“默认”列(并且您必须处理鸡和 11 个蛋的问题)!
2)另一种选择是使用触发器。
3) 另一种选择是在两个表之间使用数据库级约束。不确定是否有任何 DBMS 具有此类功能。除了典型的 UNIQUE、PRIMARY 和 FOREIGN KEY 约束之外,大多数 DBMS 仅具有行级约束和限制(无子查询等)。
4) 另一种选择是通过创建适当的 INSERT、UPDATE 和 DELETE 过程来强制执行此类规则,这些过程只能访问两个相关表并根据这些规则强制执行完整性。这是更好的方法(在我看来)。
5) 另一种更容易实现的选择是使用标准外键约束,强制执行一对多关系,并拥有一个显示实际拥有 11 名或更多玩家的团队的视图。这当然意味着您实际上并没有执行您所要求的规则。但有可能(我可以说很可能)你也负担不起。例如,如果足球运动员在事故中丧生,球队就不能再参加锦标赛,但它仍然是一支球队。因此,您可以定义两个可以玩游戏的实体:Team(基本表)和 ProperTeam(视图)。示例:
选项 1 和 2 看起来相当“混乱”,但这只是个人意见,很多人喜欢触发器。
我会选择选项 4,除非我可以(“作弊”并且)实际上不强制执行选项 5 的约束。
There is no way to enforce such rules using only
FOREIGN KEY
constraints.1) One way is by allowing circular references between tables (the "default" column, advised by jug). This results in chicken-and-egg problems that are difficult to manage, you'll have to use deferrable constraints. Plus, this option is simply not available in some DBMS. Another disadvantage is that for a football team, you'll have to add 11 "default" columns (and you'll have to deal with a chicken-and-11-eggs problem)!
2) Another option is to use triggers.
3) Another option is to use a database-level constraint between the 2 tables. Not sure if there is any DBMS that has such functionality. Besides the typical
UNIQUE
,PRIMARY
andFOREIGN KEY
constraints, most DBMS have just row level constraints and with limitations (no subqueries, etc).4) Another option is to enforce such rules by creating appropriate INSERT, UPDATE and DELETE procedures that can only access the two related tables and enforce the integrity according to these rules. This is the better approach (in my opinion).
5) One more option, simpler to implement is to use standard Foreign Key constraints, enforcing the 1-to-many relationship and have a View that shows those Teams that actually have 11 or more players. This off course mean sthat you don't actually enforce the rules you ask for. But it's possible (and may I say probable) that you can afford not too. If the football players get killed in an accident for example, the team can not longer play in tournaments but it's still a team. So, you may define two entities, the Team (the base Table) and the ProperTeam (View), that can play games. Example:
Options 1 and 2 look rather "messy" but that's only a personal opinion, many people like triggers.
I would choose Option 4, unless I can ("cheat" and) actually not enforce the constraint with Option 5.
如果您的地址位于一个表 adresses 中,则可以定义一个非空列“default_address”(在表 customers 中)。 > 必须提供的地址的外键引用。
如果您有一个表 shippings 通过引用人员、地址以及订单(-item)来提供可选的多对多关系,那么您可以使用合并来覆盖地址的 NULL您在(客户内部联接订单)和shipping_addresses之间建立了外部联接(将shippings与地址)。但是,为了防止地址中可能存在不同数量的非空组件出现问题,Stephane Faroult 在他的(强烈推荐!)一书中推荐使用“隐藏的 SQL 艺术”排序键”技术(假设 customers_with_default_address 是使用“default_address”将 customers 与 addresses 连接起来的视图:
If you have the addresses in one table adresses, you can define a column "default_address" (in the table customers) that is a non-null foreign key reference to the address that must be provided.
If you have a table shippings that provides an optional many-to-many relationship by referencing a person, an address and maybe an order(-item), then you could use coalesce to overwrite the NULLs for addresses you get in an outer join between (customers inner join orders) and shipping_addresses (a view joining shippings with addresses). But to prevent problems with maybe different numbers of non-null components of addresses, Stephane Faroult recommends in his (strongly recommended!) book The Art of SQL to use the "hidden sort key" technique (assuming that customers_with_default_address is a view joining customers with addresses using "default_address":
对我有用且需要合理数量的编码的方法是(转换为您的团队/玩家问题):
这将强制执行约束,但作为副作用,这也将只允许以一种方式对新的玩家团队进行编码(即,不会将其作为关键违规而拒绝)
请注意,我通过使用自定义主键来做到这一点(对于 teamPK),例如唯一的团队名称,以便我可以在实际将行插入表 team 之前知道 teamPK(而不是使用自动递增 id)。
The approach that worked for me and required a reasonable amount of coding was (translated to your team/player question):
This will enforce the constraint, but as a side-effect this will also allow only one way of encoding a new team of players (that is, without rejecting it as a key violation)
Note that I do that by using self-defined primary keys (for teamPK), e.g. a unique team name, so that I can know the teamPK before actually inserting the line in table team (as opposed to using the auto-incremented id).