2013-04-12 31 views
5

Đây là lần đầu tiên tôi đang cố gắng lưu trữ một đối tượng phức tạp hơn vào cơ sở dữ liệu. Tôi cần trợ giúp về thiết kế cơ sở dữ liệu.Cách cấu trúc cơ sở dữ liệu với nhiều bảng tham gia

Các recipe Object Tôi muốn để lưu trữ và tái sinh từ cơ sở dữ liệu

{ 
    "id": 2345, 
    "name": "cake", 
    "description": "yummy cake", 
    "categorys": [ 
     17, 
     26 
    ], 
    "persons": 4, 
    "author": 26, 
    "language": "de", 
    "unit": "en", 
    "variantOf": 34, 
    "specialTools": [ 
     34, 
     44, 
     10 
    ], 
    "img": "32598734.jpg", 
    "estTime": 2777, 
    "steps": { 
     "1": { 
      "title": "mix", 
      "description": "mix all together", 
      "img": "45854.jpg", 
      "timer": null, 
      "ingredients": [ 
       { 
        "name": "Butter", 
        "color": "#227799", 
        "amount": 150, 
        "unit": "g" 
       }, 
       { 
        "name": "egg", 
        "color": "#aaff22", 
        "amount": 3, 
        "unit": "pc" 
       }, 
       { 
        "name": "sugar", 
        "color": "#22ffff", 
        "amount": 50, 
        "unit": "g" 
       } 
      ] 
     }, 
     "2": { 
      "title": "bake", 
      "description": "put it in the oven", 
      "img": null, 
      "timer": 2400, 
      "ingredients": [ 
       { 
        "name": "butter", 
        "color": "#227799", 
        "amount": null, 
        "unit": null 
       }, 
       { 
        "name": "sugar", 
        "color": "#22ffff", 
        "amount": null, 
        "unit": null 
       }, 
       { 
        "name": "egg", 
        "color": "#aaff22", 
        "amount": null, 
        "unit": null 
       } 
      ] 
     } 
    } 
} 

Phần phức tạp nhất là đối tượng steps. Mỗi công thức có thể có một số bước khác nhau với các thành phần khác nhau được gán cho mỗi bộ.

Dưới đây là một thiết kế cơ sở dữ liệu tôi đã database scheme

recipe_id, step_id là chìa khóa nước ngoài. Tôi muốn tất cả mọi thứ trong các bảng khác nhau, bởi vì các công thức nấu ăn nên có thể phân loại theo nguyên liệu, chuyên cung ...

mã SQL để tạo ra bảng quan trọng nhất

-- ----------------------------------------------------- 

-- Table `dev_Recipe`.`recipe` 

-- ----------------------------------------------------- 

CREATE TABLE IF NOT EXISTS `dev_Recipe`.`recipe` (

    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT , 

    `name` VARCHAR(255) NULL , 

    `description` TEXT NULL , 

    `author_id` INT UNSIGNED NOT NULL , 

    PRIMARY KEY (`id`) , 

    INDEX `author_id_idx` (`author_id` ASC) , 

    CONSTRAINT `author_id` 

    FOREIGN KEY (`author_id`) 

    REFERENCES `dev_Recipe`.`users` (`id`) 

    ON DELETE NO ACTION 

    ON UPDATE NO ACTION) 

ENGINE = InnoDB; 



-- ----------------------------------------------------- 

-- Table `dev_Recipe`.`step` 

-- ----------------------------------------------------- 

CREATE TABLE IF NOT EXISTS `dev_Recipe`.`step` (

    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT , 

    `recipe_id` INT UNSIGNED NOT NULL , 

    `step_number` INT UNSIGNED NOT NULL , 

    `description` TEXT NULL , 

    `timer` INT UNSIGNED NULL , 

    `image` VARCHAR(100) NULL , 

    PRIMARY KEY (`id`) , 

    INDEX `recipe_id_idx` (`recipe_id` ASC) , 

    CONSTRAINT `step_recipe_id` 

    FOREIGN KEY (`recipe_id`) 

    REFERENCES `dev_Recipe`.`recipe` (`id`) 

    ON DELETE NO ACTION 

    ON UPDATE NO ACTION) 

ENGINE = InnoDB; 


-- ----------------------------------------------------- 

-- Table `dev_Recipe`.`ingredient` 

-- ----------------------------------------------------- 

CREATE TABLE IF NOT EXISTS `dev_Recipe`.`ingredient` (

    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT , 

    `name` VARCHAR(45) NOT NULL , 

    `color` INT NOT NULL , 

    `img` VARCHAR(45) NULL , 

    PRIMARY KEY (`id`)) 

ENGINE = InnoDB; 


-- ----------------------------------------------------- 

-- Table `dev_Recipe`.`step_ingredients` 

-- ----------------------------------------------------- 

CREATE TABLE IF NOT EXISTS `dev_Recipe`.`step_ingredients` (

    `recipe_id` INT UNSIGNED NOT NULL , 

    `ingredient_id` INT UNSIGNED NOT NULL , 

    `step_id` INT UNSIGNED NOT NULL , 

    `amount` INT NULL , 

    `unit` VARCHAR(25) NULL , 

    INDEX `recipe_id_idx` (`recipe_id` ASC) , 

    INDEX `ingredient_id_idx` (`ingredient_id` ASC) , 

    INDEX `step_id_idx` (`step_id` ASC) , 

    PRIMARY KEY (`recipe_id`, `step_id`) , 

    CONSTRAINT `step_ing_recipe_id` 

    FOREIGN KEY (`recipe_id`) 

    REFERENCES `dev_Recipe`.`recipe` (`id`) 

    ON DELETE NO ACTION 

    ON UPDATE NO ACTION, 

    CONSTRAINT `ingredient_step_ing_id` 

    FOREIGN KEY (`ingredient_id`) 

    REFERENCES `dev_Recipe`.`ingredient` (`id`) 

    ON DELETE NO ACTION 

    ON UPDATE NO ACTION, 

    CONSTRAINT `step_ing_id` 

    FOREIGN KEY (`step_id`) 

    REFERENCES `dev_Recipe`.`step` (`id`) 

    ON DELETE NO ACTION 

    ON UPDATE NO ACTION) 

ENGINE = InnoDB;

Vì tôi chưa bao giờ làm tham gia bảng trước đó, Tôi không biết nếu đó là cách tiếp cận đúng cho vấn đề của tôi. Nó là một thiết kế lý tưởng và làm thế nào để tối ưu hóa nó?

Tôi đã thiết kế một thiết kế khác, trong đó recipes được kết hợp với stepstep với ingredients. Tôi nghĩ bố cục đầu tiên dễ truy vấn hơn vì tôi có thể tìm kiếm theo số ingredients_idrecipe_id bằng cách chỉ xem step_ingredients, nhưng tôi không chắc chắn. Có suy nghĩ gì không?

database design 2

Trả lời

5

Điều quan trọng với thiết kế cơ sở dữ liệu quan hệ là có 3 loại mối quan hệ FK:

  • 1 đến 1
  • 1 tới nhiều
  • nhiều nhiều

Đó là cho biết, lược đồ của bạn trông cũng được chuẩn hóa và hợp lý trong nháy mắt. Sự thận trọng duy nhất mà tôi đưa ra là sự đệ quy có thể phức tạp trong SQL đối với các danh mục có tham chiếu tự.

Một vài lưu ý:

Một thành phần bước đòi hỏi một bước mà đã có một recipe_id (có thể null)

một thành phần bước có thể tồn tại mà không có một bước

Một bước có thể tồn tại mà không có một recipe

Người dùng làm công thức là một (một) (như Dan được đề cập)

Chỉnh sửa: Đối với mối quan tâm về việc ghép đôi thay vì tham gia duy nhất để đi từ công thức đến thành phần, đây là một mối quan tâm bình thường hóa tôi với thiết kế ban đầu: điều gì giữ step_ingredient và bước recipe_id là như nhau? Ngay bây giờ, sẽ không có sự đảm bảo nào về tính nhất quán. Nếu bạn xem xét thiết kế dữ liệu bạn thực sự nói bạn nghĩ rằng bạn sẽ tham gia hai bảng này rất nhiều nên tại sao không kết nối chúng với một FK không cần thiết (không làm điều này hoặc mọi thứ sẽ nhanh chóng lộn xộn :))

thiết kế thứ hai thực sự cũng cho phép cùng số lượng kết nối vì bạn đã bao gồm recipe_id dưới dạng PK trong bảng bước mà sau đó trở thành PK/FK trong step_ingredient và nó sẽ đảm bảo tính nhất quán recipe_id. ví dụ:

SELECT ingredient_id 
FROM Recipe r 
JOIN Step_ingredient si on si.step_recipe_id = r.recipe_id 
JOIN Ingredient i on si.ingredient_id = i.ingredient_id 

và liên kết yêu thích của tôi để bắt đầu với chuẩn hóa dữ liệu: http://en.wikipedia.org/wiki/Database_normalization

+0

Cảm ơn bạn đã trả lời. Bạn có thể đề xuất một cách tốt hơn để tổ chức các danh mục phụ không? Nó sẽ là tốt hơn để hạn chế mức độ tiểu thể loại và tạo ra một bảng cho mỗi lớp? Tôi không hoàn toàn nhận được những gì bạn muốn nói với "Có thể một thành phần bước tồn tại mà không có một bước". Thành phần 'bước 'không tồn tại mà không có' bước'. Và một 'bước' nên thuộc về một công thức. – Akkumulator

+1

Trong trường hợp đó, một thành phần bước không nên cần một kết nối trực tiếp đến công thức, và một bước nên yêu cầu một FK để một công thức. Tiểu thể loại có thể phức tạp trong sql, có nhiều cách khác nhau để tổ chức các cấu trúc giống cây http://stackoverflow.com/questions/2175882/how-to-represent-a-data-tree-in-sql. Nếu bạn biết độ sâu của việc phân loại, có thể dễ dàng hơn để tạo các bảng được san bằng. – munch1324

+0

Bạn có nghĩ sơ đồ thứ hai của tôi, tôi đã thêm vào sau, sẽ tốt hơn không? – Akkumulator

2

Thoạt nhìn, nó trông rất đẹp. Tuy nhiên, tôi không chắc tại sao bảng danh mục và thành phần cần id mẹ.

Ngoài ra, bạn sẽ cần mối quan hệ nhiều đến nhiều giữa người dùng và công thức nấu ăn. Bạn hiện có những gì trông giống như một.

+0

id cha mẹ đang có cho subcategorys. Nếu một danh mục tham chiếu một danh mục khác thì đó là danh mục phụ. nếu 'parent_id' bằng' Null' thì đó là danh mục chính. Tôi chưa từng xử lý việc xử lý người dùng. Nhưng cảm ơn vì đã chỉ ra điều đó :) – Akkumulator

+1

Thay vì vô hiệu hóa id mẹ cho các danh mục chính, tôi sẽ cung cấp cho nó giá trị giống như id danh mục. Các giá trị rỗng trong các trường khóa ngoài có thể được cho phép trong một số cơ sở dữ liệu, nhưng chúng làm tôi sai đường. –

Các vấn đề liên quan