我可以避免这个外键中的“冗余”吗?

时间:2016-10-08 13:24:48

标签: sql

我正在尝试设计一个数据库,我的一个表是这样的:

player_in_tournament

    import { Component } from '@angular/core';
     import { ROUTER_DIRECTIVES } from '@angular/router';
import {Http} from '@angular/http';
import { CookieService } from 'angular2-cookie/services/cookies.service';
import { FORM_PROVIDERS } from '@angular/forms';

import { TRANSLATION_PROVIDERS} from '../../translate/translation';
import { TranslateService } from '../../translate/translate.service';
import { TranslatePipe } from '../../translate/translate.pipe';

@Component({
    selector: 'my-app',
    template:
        `<div>
            <router-outlet></router-outlet>
            <app-dashboard></app-dashboard>
            <app-login></app-login>
        </div>`,
    directives: [ROUTER_DIRECTIVES],
    pipes: [TranslatePipe],
    providers: [CookieService, FORM_PROVIDERS, TRANSLATION_PROVIDERS, TranslateService],
})

export class AppComponent {
    public constructor(private http: Http, private _translate: TranslateService) {
        /* Setting default lanaguage. */
        switch(navigator.language) {
            case 'de' : {
                _translate.use('de');
                break;
            }
            default: {
                _translate.use('en');
            }
        }
    }

    public requestAPI = function() {
        return this.http;
    }
}

并且PK由两个第一列组成。

在表ID_tourn | ID_player | and other attributes... (表示比赛的比赛/比赛)中,我想引用player_in_tournament中的2个“对象”,所以我应该有两个外键,每个外键由一个ID_player和ID_tour。

tournament_game在两个“对象”中都是相同的。

问题是,更改第一个表的PK并添加ID_tour是否是个好主意,并在ID_player_in_tournament表中使用它作为外键。

4 个答案:

答案 0 :(得分:1)

player_in_tournament表添加代理键可以构建代表具有两个不同tournament_game的玩家的ID_tourn。这样可以避免冗余,但会造成不一致。

您应该有三个字段参与两个外键 -

  • (ID_tourn, ID_player1)代表第一个player_in_tournament
  • (ID_tourn, ID_player2)代表第二个player_in_tournament

请注意,同一列ID_tourn参与两个外键关系:

create table player_in_tournament(
    ID_tourn int
,   ID_player int
,   ...
,   primary key(ID_tourn, ID_player)
);
create table tournament_game(
    ID_tourn int
,   ID_player1 int
,   ID_player2 int
,   ...
,   foreign key (ID_tourn, ID_player1)
        references player_in_tournament(ID_tourn, ID_player)
,   foreign key (ID_tourn, ID_player2)
        references player_in_tournament(ID_tourn, ID_player)
);

答案 1 :(得分:1)

首先,你有一场锦标赛。您已经为它提供了一个名为ID_tourn的人工识别器。这可能是因为没有像锦标赛2016Q3那样的真实姓名或号码。 (如果是的话,你可以使用这个锦标赛号码并且不必人工添加ID。)

然后你有球员。在这里,您再次创建一个ID。可能是因为他们是现实生活中没有任何自然识别号码的玩家。 (如果他们只是你游戏中的玩家,他们会有一个你可以使用的登录名或用户名。)

现在你有参加比赛的球员。记录由锦标赛标识符和玩家标识符自然识别。

最后你有一个锦标赛游戏,显然是两个锦标赛玩家的比赛。因此,记录将包含锦标赛标识符和两个玩家标识符。它将包含两个外键:ID_tourn + ID_player1和ID_tourn + ID_player2。

所有这些,在可能的情况下使用复合键和自然键(如登录名)是创建数据库的一个概念。另一个是为每个表提供一个人工ID和链接表。我曾在大型数据库上工作过,并且更喜欢第一个概念,但还有其他人喜欢全ID的概念。

这是两个比较的例子。 PK =主键,FKn =外键,PK2 =唯一约束(如第二个PK)

自然键/复合键

  • table client(client_number) =&gt; PK(客户)
  • 表项(item_number,说明,价格) =&gt; PK(ITEM_NUMBER)
  • 表格顺序(order_number,order_date,client_number) =&gt; PK(ORDER_NUMBER); FK1(client.client_number)
  • table order_item(order_number,item_number,amount) =&gt; PK(ORDER_NUMBER,ITEM_NUMBER); FK1(order.order_number); FK2(item.item_number)

人工ID

  • table client(id_client,client_number) =&gt; PK(id_client); PK2(客户)
  • 表项(id_item,item_number,描述,价格) =&gt; PK(id_item); PK2(ITEM_NUMBER)
  • 表格顺序(id_order,order_number,order_date,client_number) =&gt; PK(id_order); PK2(order_number),FK1(client.client_number)
  • table order_item(id_order_item,order_number,item_number,amount) =&gt; PK(id_order_item); PK2(ORDER_NUMBER,ITEM_NUMBER); FK1(order.order_number); FK2(item.item_number)

答案 2 :(得分:0)

正如你所猜测的那样,这将使表tournament_game中的外键只有两列宽而不是四列,这将提高你需要在SQL语句中编写的连接的便利性和可读性。唯一的缺点是表宽度的增加,但每行只有几个字节。正如您所知,这被称为代理键&#34; (而不是&#34;自然键&#34;)。 如果这样做,请确保在&#34;自然键&#34;上留下唯一的键或约束。 (ID_tourn, ID_player)确保这两个字段保持唯一性并且表保留数据一致性。

答案 3 :(得分:0)

这里有2个表table_in_tournament和tournament_game。顾名思义,tournament_game是游戏中锦标赛的表格,因此它应该有锦标赛ID和锦标赛名称以及与锦标赛相关的所有其他属性。另一个表player_in_tournament应该有玩家ID,玩家名称和锦标赛ID(来自tournament_game表的参考)以及与玩家相关的其他属性。这应该根据您的查询进行设计。