使用外键进行适当的数据库设计

时间:2017-06-30 17:56:34

标签: database postgresql

因为我从未设计过数据库,所以我想确保我使用的设计虽然简单,但却遵循一般的惯用设计模式。

基本上,一位朋友正在制作一个不和谐机器人,允许您提交照片并让其他人评价。将明显的拖钓机会放在一边,这里是需要的数据字段:

  • Discord ID(每个使用不和的人的唯一ID)
  • 网址列表(每个网址与某个不和谐成员相关联)
  • 投票列表(每个投票有分数,选民ID和URL)

我对此设计并不特别喜欢它保留了两个分数:一个总分,将除以该用户的总票数,特别是每个分数。

我的问题是:

  1. 这个设计是否合适?
  2. 使用此设计,我如何确保每个人只能为每个网址投票一次?
  3. Database Design

    https://dbdesigner.net输出:

    CREATE TABLE "Members" (
        "id" serial NOT NULL,
        "discord_id" bigint NOT NULL,
        "total_score" bigint NOT NULL,
        "total_votes" bigint NOT NULL,
        CONSTRAINT Members_pk PRIMARY KEY ("id")
    ) WITH (
      OIDS=FALSE
    );
    
    CREATE TABLE "Images" (
        "id" serial NOT NULL,
        "url" TEXT(64) NOT NULL,
        "member_id" bigint NOT NULL,
        CONSTRAINT Images_pk PRIMARY KEY ("id")
    ) WITH (
      OIDS=FALSE
    );
    
    CREATE TABLE "Votes" (
        "id" serial NOT NULL,
        "voter_id" serial NOT NULL,
        "target_id" serial NOT NULL,
        "score" serial NOT NULL,
        "image_id" serial NOT NULL,
        CONSTRAINT Votes_pk PRIMARY KEY ("id")
    ) WITH (
      OIDS=FALSE
    );
    
    
    ALTER TABLE "Images" ADD CONSTRAINT "Images_fk0" FOREIGN KEY ("member_id") REFERENCES "Members"("discord_id");
    
    ALTER TABLE "Votes" ADD CONSTRAINT "Votes_fk0" FOREIGN KEY ("voter_id") REFERENCES "Members"("discord_id");
    ALTER TABLE "Votes" ADD CONSTRAINT "Votes_fk1" FOREIGN KEY ("target_id") REFERENCES "Members"("discord_id");
    ALTER TABLE "Votes" ADD CONSTRAINT "Votes_fk2" FOREIGN KEY ("image_id") REFERENCES "Images"("id");
    

2 个答案:

答案 0 :(得分:2)

由于我看不到您的外键引用而且我没有看到您的代码(即SQL语句),我无法确定您的合成键是否是个好主意。但乍看之下,看起来VOTES的真正关键是(VOTER_ID,IMAGE_URL)。

如果我们假设你不打算改变关系,它们的键和它们的非键属性,那么你需要做的就是满足#2是对VOTES(VOTER_ID,IMAGE_URL)设置唯一约束。

答案 1 :(得分:1)

回答问题的第一部分,"这个设计是否正确",简短的回答是" no"。

  1. 如果discord_ids是唯一的,则成员中不需要其他ID列。 discord_id是成员表的主键。
  2. 如果图片网址是唯一的,则可以成为Images表的主键。这真的取决于你;有些人不喜欢使用长文本字符串作为键。我假设你是其中之一。
  3. 投票表根本不应该有ID列。它是一个多对多的连接表。你的密钥是(voter_id,image_id)。这也可以防止成员多次投票。
  4. 投票中的target_id列完全是多余的,因为该信息已存在于图像表中。
  5. 投票中的voter_id和image_id都不应该是Serial。相反,它们应该是INT。分数(可能是数字分数)应该是NUMERIC或INT(我使用INT,因为total_score是bigint)。
  6. 在SQL中使用混合大小写标识符通常是个坏主意,因为标识符(表)名称在奇怪的情况下区分大小写。
  7. 将网址限制为64个字符似乎是短视的;你在这里需要匹配应用程序约束吗?
  8. 您应该将CASCADE添加到所有foriegn键中,以便您可以轻松删除成员或图像。
  9. 因此,下面是您修改后的架构:

    CREATE TABLE "members" (
        "discord_id" bigint NOT NULL,
        "total_score" bigint NOT NULL,
        "total_votes" bigint NOT NULL,
        CONSTRAINT members_pk PRIMARY KEY ("discord_id")
    );
    
    CREATE TABLE "images" (
        "id" serial NOT NULL,
        "url" VARCHAR(64) NOT NULL,
        "discord_id" BIGINT NOT NULL,
        CONSTRAINT images_pk PRIMARY KEY ("id"),
        CONSTRAINT images_url UNIQUE ("url")
    );
    
    CREATE TABLE "votes" (
        "voter_id" INT NOT NULL,
        "image_id" INT NOT NULL,
        "score" INT NOT NULL,
        CONSTRAINT votes_pk PRIMARY KEY (voter_id, image_id)
    );
    
    ALTER TABLE "images" ADD CONSTRAINT "images_fk0" 
    FOREIGN KEY ("discord_id") REFERENCES "members"("discord_id")
    ON DELETE CASCADE ON UPDATE CASCADE;
    ALTER TABLE "votes" ADD CONSTRAINT "votes_fk0" 
    FOREIGN KEY ("voter_id") REFERENCES "members"("discord_id")
    ON DELETE CASCADE ON UPDATE CASCADE;
    ALTER TABLE "votes" ADD CONSTRAINT "votes_fk2" 
    FOREIGN KEY ("image_id") REFERENCES "images"("id")
    ON DELETE CASCADE ON UPDATE CASCADE;