Bình thường hóa một bảng với một trường thường xác định duy nhất một hàng, nhưng đôi khi là null


7

tha thứ cho tôi nếu điều này đã được hỏi và trả lời trước

Tôi đang phác thảo một lược đồ cho một hệ thống quản lý hàng tồn kho, sẽ được triển khai trong PostgreSQL. Tất cả các sản phẩm và dịch vụ của chúng tôi có một sku. Hầu hết các sản phẩm của chúng tôi đến từ nhà sản xuất hoặc nhà phân phối với một "số mặt hàng" riêng biệt (cho dù đó là số danh mục của nhà phân phối, số kiểu của nhà sản xuất, bất cứ thứ gì). Tuy nhiên, không phải tất cả trong số họ có một số như vậy. Chúng tôi có các hội đồng nhỏ mà chúng tôi làm trong nhà, nói chung, không có số vật phẩm. Dịch vụ của chúng tôi không có số mặt hàng. Vì những lý do này, BẢNG TẠO sau đây có ý nghĩa với tôi.

Kịch bản A:

CREATE TABLE product (
   sku            text PRIMARY KEY,
   name           text UNIQUE NOT NULL, -- alternate key
   price          numeric NOT NULL CHECK (price > 0),
   quantity       numeric NOT NULL CHECK (quantity > 0),
   item_number   text -- hmmm...
);

Tuy nhiên, tôi có hai vấn đề với điều này.

  1. Đôi khi (có thể 3% đến 5% thời gian), item_number thực sự bằng SKU. Đó là, một trong những nhà cung cấp của tôi đặc biệt gắn liền với các sản phẩm của họ, điều mà tôi nghi ngờ không phải là một SKU duy nhất trên toàn cầu, được đặt theo số mặt hàng của họ.

  2. Dù có bằng SKU hay không, item_number (khi tồn tại) trong hầu hết mọi trường hợp đủ để xác định duy nhất một sản phẩm trong miền của cửa hàng nhỏ của tôi.

Tôi lo lắng về việc bình thường hóa điều này thành 3NF. Nếu item_number đôi khi là null, rõ ràng nó không thể được khai báo là khóa thay thế. Nhưng, về mặt ngữ nghĩa, nó là một định danh duy nhất, nơi nó tồn tại, trong mọi trường hợp tôi có thể nghĩ ra. Vậy bảng trên của tôi, nơi mọi thuộc tính đều phụ thuộc chức năng vào thuộc tính không phải là số nguyên tố item_number bất cứ khi nào item_number tồn tại , được chuẩn hóa? Tôi nghĩ là không, nhưng tôi chắc chắn không phải là một chuyên gia. Tôi nghĩ làm như sau:

Kịch bản B

CREATE TABLE product (
   sku            text PRIMARY KEY REFERENCES product_item_number (sku),
   name           text UNIQUE NOT NULL, -- alternate key
   price          numeric NOT NULL CHECK (price > 0),
   quantity       numeric NOT NULL CHECK (quantity > 0),
);

CREATE TABLE product_item_number (
   sku            text PRIMARY KEY,
   item_number    text
);

Vì đó thực sự không phải là một yêu cầu mà tôi duy trì sự phụ thuộc chức năng item_number -> price, item_number -> số lượng, v.v., kịch bản B kinda sorta có vẻ hợp lý với tôi. Tôi sẽ không có thuộc tính không phải là số nguyên tố xác định bất kỳ thuộc tính không chính nào khác.

Ý tưởng cuối cùng của tôi là chỉ đơn giản là sử dụng sku làm số vật phẩm trong tất cả các trường hợp trong đó item_number không tồn tại, nhưng tôi tự hỏi liệu đó có phải là một thực hành tốt hay không.

Kịch bản C

CREATE TABLE product (
   sku            text PRIMARY KEY,
   name           text UNIQUE NOT NULL, -- alternate key
   price          numeric NOT NULL CHECK (price > 0),
   quantity       numeric NOT NULL CHECK (quantity > 0),
   item_number    text UNIQUE NOT NULL -- alternate key???
);

Mối quan tâm của tôi với kịch bản C là có thể có trường hợp nhà cung cấp tái chế số danh mục với một sku khác nhau (có thể?), Hoặc tình huống hai nhà sản xuất đều tạo ra "d57-red" hoặc đại loại như thế. Trong trường hợp đó, tôi nghĩ rằng tôi phải lập trình tiền tố xúc phạm item_numbers với tên nhà sản xuất hoặc đại loại như thế.

Tất nhiên, có lẽ tôi đang nghĩ quá nhiều về điều này.

Cảm ơn vì đã đọc. Một vài làm rõ, theo nhận xét của MDCCL:

  • Một sku sẽ luôn là duy nhất trong miền của tôi (Một lượng nhỏ SKU do nhà cung cấp duy nhất không cung cấp trên toàn cầu không có khả năng va chạm).
  • Item_number sẽ là một thuộc tính công khai, được sử dụng bởi cả khách hàng và đôi khi chính tôi để xác định sản phẩm. Ví dụ: giả sử một khách hàng bỏ qua trang web của tôi và gọi cho tôi để hỏi liệu tôi có xyz-trắng không; item_number giúp loại bỏ sự mơ hồ. Các số vật phẩm là duy nhất theo kinh nghiệm của tôi (nghĩa là không có ví dụ truy cập nào trong kho của tôi), nhưng đó không phải là quy tắc. Tôi có thể có một vụ va chạm không gian tên item_number một ngày. Có lẽ, nếu điều đó xảy ra, tôi sẽ đặt tiền tố ba chữ cái đầu tiên của tên nhà sản xuất vào item_number.
  • item_numbers không tồn tại. Tôi cho rằng tôi có thể cung cấp một số loại "thay thế item_number" cho những người không có ai, nhưng một item_number tùy ý sẽ phản tác dụng. Như đã giải thích ngay ở trên, nơi tồn tại một item_number, nó sẽ tồn tại để giúp bản thân tôi và khách hàng của tôi phân tán giữa các sản phẩm. Họ có thể tin rằng họ đang nhìn nhầm sản phẩm nếu item_number là thứ tôi tự pha chế. Tôi không chắc.

Câu trả lời:


9

Với điều kiện SkuItemNumber sẽ luôn bao hàm các giá trị duy nhất

Tôi cho rằng bạn đã tìm thấy câu trả lời bằng cách khám phá ra rằng, về mặt khái niệm, ItemNumber là một thuộc tính tùy chọn ; tức là, khi bạn xác định rằng nó không áp dụng cho từng trường hợp xuất hiện, được biểu thị bằng các hàng ở mức logic logic của loại thực thể Sản phẩm . Do đó, item_numbercột không nên được khai báo dưới dạng ALTERNATE KEY (AK for brevity) trong productbảng, như bạn đã chỉ ra một cách đúng đắn.

Về mặt này, Kịch bản B của bạn khá hợp lý, vì công thức ở cấp độ khái niệm sau đây thể hiện:

  • Một sản phẩm có thể có hoặc không có số mặt hàng .

Nói cách khác, có một tỷ lệ cardinality từ 1 đến 0 hoặc 1 (1: 0/1) giữa ProductItemNumber .

Sau đó, vâng, bạn nên giới thiệu một bảng mới để xử lý cột tùy chọn và tôi đồng ý rằng đó product_item_numberlà một tên rất mô tả cho nó. Bảng này phải được skuràng buộc là KHÓA CHÍNH (PK) của nó, để đảm bảo rằng không có nhiều hơn một hàng có cùng skugiá trị được chèn vào nó, giống như bạn đã làm.

Điều quan trọng nữa là phải đề cập đến điều đó product_item_number.skucũng nên bị ràng buộc như là một NGOẠI TỆ (FK) làm tham chiếu đến product.sku.

Dưới đây là một thiết kế mức logic SQL-DDL mẫu minh họa các đề xuất trước đó:

-- You should determine which are the most fitting 
-- data types and sizes for all your table columns 
-- depending on your business context characteristics.

-- Also, you should make accurate tests to define
-- the most convenient INDEXing strategies.

CREATE TABLE product ( 
    sku      TEXT    NOT NULL, 
    name     TEXT    NOT NULL, 
    price    NUMERIC NOT NULL, 
    quantity NUMERIC NOT NULL,
    --
    CONSTRAINT product_PK        PRIMARY KEY (sku), 
    CONSTRAINT product_AK        UNIQUE      (name), -- AK.
    CONSTRAINT valid_price_CK    CHECK       (price > 0),
    CONSTRAINT valid_quantity_CK CHECK       (quantity > 0)
); 

CREATE TABLE product_item_number ( 
    sku         TEXT NOT NULL, -- To be constrained as PK and FK to ensure the 1:0/1 correspondence ratio between the relevant rows.
    item_number TEXT NOT NULL, 
    --
    CONSTRAINT product_item_number_PK            PRIMARY KEY (sku),
    CONSTRAINT product_item_number_AK            UNIQUE      (item_number), -- In this context, ‘item_number’ is an AK. 
    CONSTRAINT product_item_number_TO_product_FK FOREIGN KEY (sku) 
        REFERENCES product (sku)  
);

Đã thử nghiệm trên PostgreSQL 11 trong db <> fiddle này .

Ngoài ra, có một công thức khái niệm khác hướng dẫn trong việc định hình thiết kế cơ sở dữ liệu được trình bày ở trên:

  • Nếu nó tồn tại, ItemNumber của sản phẩm phải là duy nhất.

Vì vậy, trong đó item_numbercột thực sự phải được khai báo là AK ở ngay đó, trong product_item_numberbảng, bởi vì cột đã nói chỉ yêu cầu bảo vệ tính duy nhất khi giá trị thích hợp được cung cấp, do đó các ràng buộc UNIQUE và KHÔNG NULL phải được cấu hình tương ứng.

Thiếu giá trị và phiên dịch thế giới khép kín

Sự sắp xếp SQL-DDL hợp lý được mô tả trước đây là một ví dụ về cách tiếp cận quan hệ để xử lý các giá trị bị thiếu, mặc dù nó không phải là cách phổ biến nhất của Wapor thông thường. Cách tiếp cận này có liên quan đến Phiên dịch thế giới khép kín Thông qua vị trí này, (a) thông tin được ghi trong cơ sở dữ liệu luôn được coi là đúng và (b) thông tin không được ghi trong đó luôn luôn được coi là sai . Theo cách này, người ta chỉ giữ lại những sự thật được biết đến .

Trong kịch bản kinh doanh hiện tại, khi người dùng cung cấp tất cả các điểm dữ liệu được bao gồm trong productbảng, bạn phải XÁC NHẬN hàng tương ứng và nếu, và chỉ khi, người dùng tạo item_numberdữ liệu có sẵn, bạn cũng phải CHỌN product_item_numberđối tác. Trong trường hợp item_numbergiá trị không xác định hoặc đơn giản là nó không áp dụng, bạn không XÁC NHẬN một product_item_numberhàng và đó là giá trị đó.

Với phương pháp này, bạn tránh giữ các dấu / đánh dấu NULL trong các bảng cơ sở của mình và các hậu quả ở mức logic mà tôi sẽ trình bày chi tiết trong phần tiếp theo, nhưng bạn nên biết rằng đây là một chủ đề gây tranh cãi trong một phạm vi quản trị cơ sở dữ liệu. Về điểm này, bạn có thể tìm thấy giá trị các câu trả lời cho câu hỏi Stack Overflow có tên:

Quá trình hành động phổ biến

Tuy nhiên, tôi đoán rằng tiến trình phổ biến của trò chơi phổ biến của người Viking sẽ là có một productbảng duy nhất bao gồm item_numbercột, lần lượt, sẽ được đặt là NULLable, đồng thời, được xác định bằng một ràng buộc KHÔNG GIỚI HẠN. Theo cách tôi thấy, cách tiếp cận này sẽ làm cho cơ sở dữ liệu của bạn và các thao tác thao tác dữ liệu hiện hành trở nên kém thanh lịch (như được hiển thị, ví dụ, trong câu trả lời Stack Overflow nổi bật này ), nhưng đó là một khả năng.

Xem các tuyên bố DDL liên tiếp minh họa cho quá trình hành động này:

CREATE TABLE product ( 
    sku         TEXT    NOT NULL, 
    name        TEXT    NOT NULL, 
    price       NUMERIC NOT NULL, 
    quantity    NUMERIC NOT NULL, 
    item_number TEXT    NULL, -- Accepting NULL marks. 
    --
    CONSTRAINT product_PK        PRIMARY KEY (sku), 
    CONSTRAINT product_AK1       UNIQUE      (name), -- AK.
    CONSTRAINT product_AK2       UNIQUE      (item_number), -- Being ‘NULLable’, this is not an AK. 
    CONSTRAINT valid_price_CK    CHECK       (price > 0),
    CONSTRAINT valid_quantity_CK CHECK       (quantity > 0)
);

Đã thử nghiệm trên PostgreSQL 11 trong db <> fiddle này .

Vì vậy, khi đã thiết lập item_numbernhư một cột có thể chứa NULL, không đúng khi nói, về mặt logic, đó là một AK. Hơn nữa, bạn sẽ lưu trữ các dấu NULL mơ hồkhông phải là giá trị, cho dù tài liệu PostgreQuery có gắn nhãn theo cách đó hay không, do đó có thể lập luận rằng bảng sẽ không thể hiện đúng về một quan hệ toán học và quy tắc chuẩn hóa phù hợp được áp dụng cho nó.

Vì NULL chỉ ra rằng giá trị cột là (1) không xác định hoặc (2) không thể áp dụng , nên không thể nói chính xác rằng dấu đã nói thuộc về item_numbermiền giá trị hợp lệ. Như bạn đã biết, loại nhãn hiệu này nói lên điều gì đó về trạng thái của người Bỉ về một giá trị thực, nhưng bản thân nó không phải là một giá trị và, tự nhiên, nó không hành xử như vậy, và thật đáng để đề cập đến Các NULL hoạt động khác nhau trên các hệ thống quản lý cơ sở dữ liệu SQL riêng biệt, thậm chí trên các phiên bản khác nhau của cùng một hệ thống quản lý cơ sở dữ liệu.

Sau đó, nếu (i) miền của các giá trị của một cột nhất định và (ii) ý nghĩa mà cột nói đó mang lại không hoàn toàn rõ ràng do kết quả của việc bao gồm các NULL:

  • Làm thế nào người ta có thể đánh giá và xác định các phụ thuộc chức năng có liên quan?

  • Làm thế nào nó có thể được xác định và khai báo là CHÍNH HÃNG hoặc THAY ĐỔI (như trong trường hợp item_number)?

Mặc dù cả hai đều có lý thuyếtthực tế về thao túng dữ liệu, ngụ ý về việc lưu giữ các dấu NULL trong cơ sở dữ liệu, đây là cách tiếp cận để xử lý dữ liệu bị thiếu mà bạn sẽ tìm thấy trong phần lớn các cơ sở dữ liệu được xây dựng trên nền tảng SQL, vì nó cho phép gắn các cột cho các giá trị tùy chọn vào các bảng cơ sở có ý nghĩa và, như một hiệu ứng, xóa bỏ việc tạo ra (a) một bảng bổ sung và (b) các nhiệm vụ liên quan.

Quyết định

Tôi đã trình bày hai phương án để bạn có thể tự xác định xem cái nào phù hợp hơn để đạt được mục tiêu của mình.


Giả sử rằng các SkuItemNumber giá trị cuối cùng có thể được nhân đôi

Có một số điểm trong câu hỏi của bạn thu hút sự chú ý của tôi theo một cách cụ thể, vì vậy tôi đã liệt kê chúng:

  • Đôi khi (có thể 3% đến 5% thời gian), item_number thực sự bằng SKU. Đó là, một trong những nhà cung cấp của tôi đặc biệt gắn liền với các sản phẩm của họ, điều mà tôi nghi ngờ không phải là một SKU duy nhất trên toàn cầu, được đặt theo số mặt hàng của họ.

  • [V]] có thể có trường hợp nhà cung cấp tái chế số danh mục với một sku khác nhau (có thể?), Hoặc tình huống hai nhà sản xuất đều tạo ra "d57-red" hoặc đại loại như thế. Trong trường hợp đó, tôi nghĩ rằng tôi phải lập trình tiền tố xúc phạm item_numbers với tên nhà sản xuất hoặc đại loại như thế.

  • Một sku sẽ luôn là duy nhất trong miền của tôi (Một lượng nhỏ SKU do nhà cung cấp duy nhất không cung cấp trên toàn cầu không có khả năng va chạm).

Những điểm đó có thể có tác động đáng chú ý vì dường như chúng gợi ý rằng:

  • Các giá trị ItemNumber cuối cùng có thể trở thành trùng lặp và khi điều đó xảy ra, bạn có thể đánh giá việc kết hợp hai mẩu thông tin khác nhau mang ý nghĩa khác nhau trong cùng một cột.

  • Có thể, sau tất cả, các giá trị Sku có thể được lặp lại (ngay cả khi đó là một lượng nhỏ các trường hợp Sku lặp lại ).

Về vấn đề này, cần lưu ý rằng hai mục tiêu tối quan trọng của bài tập mô hình hóa dữ liệu là (1) xác định từng mốc dữ liệu quan trọng và (2) ngăn chặn việc giữ lại nhiều hơn một trong số chúng trong cùng một cột. Các yếu tố này, ví dụ, tạo điều kiện cho việc phân định cấu trúc cơ sở dữ liệu ổn định và linh hoạt và hỗ trợ trong việc tránh thông tin trùng lặp. Giúp làm gì để duy trì các giá trị dữ liệu phù hợp với quy tắc kinh doanh, thông qua các ràng buộc tương ứng.

Thay thế để xử lý các bản sao Sku : Giới thiệu manufacturerbảng cho kịch bản

Do đó, với điều kiện có thể chia sẻ cùng một giá trị Sku giữa các Nhà sản xuất khác nhau , bạn có thể sử dụng ràng buộc PK tổng hợp trong productbảng và nó sẽ được tạo thành từ (i) cột PK của nhà sản xuất và (ii) sku. Ví dụ:

CREATE TABLE manufacturer (
    manufacturer_number INTEGER  NOT NULL, -- This could be something more meaningful, e.g., ‘manufacturer_code’.
    name                TEXT NOT NULL,
    --
    CONSTRAINT manufacturer_PK PRIMARY KEY (manufacturer_number), 
    CONSTRAINT manufacturer_AK UNIQUE      (name) -- AK.
);

CREATE TABLE product (
    manufacturer_number INTEGER NOT NULL, 
    sku                 TEXT    NOT NULL,
    name                TEXT    NOT NULL, 
    price               NUMERIC NOT NULL,
    quantity            NUMERIC NOT NULL,
    --
    CONSTRAINT product_PK                 PRIMARY KEY (manufacturer_number, sku), -- Composite PK.
    CONSTRAINT product_AK                 UNIQUE      (name), -- AK.
    CONSTRAINT product_TO_manufacturer_FK FOREIGN KEY (manufacturer_number)
        REFERENCES manufacturer (manufacturer_number),
    CONSTRAINT valid_price_CK             CHECK       (price > 0),
    CONSTRAINT valid_quantity_CK          CHECK       (quantity > 0)
);

Và, nếu ItemNumber yêu cầu bảo toàn tính duy nhất khi áp dụng , thì product_item_numberbảng có thể được cấu trúc như sau:

CREATE TABLE product_item_number (
    manufacturer_number INTEGER NOT NULL,  
    sku                 TEXT    NOT NULL,
    item_number         TEXT    NOT NULL,
    --
    CONSTRAINT product_item_number_PK            PRIMARY KEY (manufacturer_number, sku), -- Composite PK.
    CONSTRAINT product_item_number_AK            UNIQUE      (item_number), -- AK.  
    CONSTRAINT product_item_number_TO_product_FK FOREIGN KEY (manufacturer_number, sku)
        REFERENCES product (manufacturer_number, sku)  
);

Đã thử nghiệm trên PostgreSQL 11 trong db <> fiddle này .

Trong trường hợp đó ItemNumber nào không yêu cầu bản sao ngăn chặn, bạn chỉ cần loại bỏ các hạn chế UNIQUE tuyên bố cho một cột như vậy, như thể hiện trong các câu lệnh DDL tiếp theo:

CREATE TABLE product_item_number (
    manufacturer_number INTEGER NOT NULL,  
    sku                 TEXT    NOT NULL,
    item_number         TEXT    NOT NULL, -- In this case, ‘item_number’ does not require a UNIQUE constraint.
    --
    CONSTRAINT product_item_number_PK            PRIMARY KEY (manufacturer_number, sku), -- Composite PK.
    CONSTRAINT product_item_number_TO_product_FK FOREIGN KEY (manufacturer_number, sku)
        REFERENCES product (manufacturer_number, sku)  
);

Mặt khác, giả rằng ItemNumber không thực sự đòi hỏi tránh các giá trị lặp đi lặp lại độc quyền liên quan đến các liên Hãng sản xuất , bạn có thể thiết lập một UNIQUE chế tổng hợp trong đó sẽ bao gồm manufacturer_numberitem_number, như đã chứng minh trong các dòng mã bên dưới:

CREATE TABLE product_item_number (
    manufacturer_number INTEGER NOT NULL,  
    sku                 TEXT    NOT NULL,
    item_number         TEXT    NOT NULL,
    --
    CONSTRAINT product_item_number_PK            PRIMARY KEY (manufacturer_number, sku),         -- Composite PK.
    CONSTRAINT product_item_number_AK            UNIQUE      (manufacturer_number, item_number), -- Composite AK.
    CONSTRAINT product_item_number_TO_product_FK FOREIGN KEY (manufacturer_number, sku)          -- Composite FK.
        REFERENCES product (manufacturer_number, sku)  
);

Khi các giá trị Sku luôn là duy nhất nhưng một giá trị ItemNumber cụ thể có thể được chia sẻ giữa các Nhà sản xuất riêng biệt

Nếu bạn có thể đảm bảo rằng Product.Sku sẽ không bao giờ có nghĩa bản sao nhưng một ItemNumber có thể được sử dụng bởi riêng biệt nhà sản xuất , bạn có thể cấu hình cơ sở dữ liệu của bạn như tiếp xúc ở đây:

CREATE TABLE manufacturer (
    manufacturer_number INTEGER NOT NULL, 
    name                TEXT    NOT NULL,
    --
    CONSTRAINT manufacturer_PK PRIMARY KEY (manufacturer_number), 
    CONSTRAINT manufacturer_AK UNIQUE      (name) -- AK.
);

CREATE TABLE product ( 
    sku      TEXT    NOT NULL, 
    name     TEXT    NOT NULL, 
    price    NUMERIC NOT NULL, 
    quantity NUMERIC NOT NULL,
    --
    CONSTRAINT product_PK        PRIMARY KEY (sku), 
    CONSTRAINT product_AK        UNIQUE      (name), -- AK. 
    CONSTRAINT valid_price_CK    CHECK       (price > 0),
    CONSTRAINT valid_quantity_CK CHECK       (quantity > 0)
); 

CREATE TABLE product_item_number ( 
    sku                 TEXT    NOT NULL,
    manufacturer_number INTEGER NOT NULL,
    item_number         TEXT    NOT NULL,
    --
    CONSTRAINT product_item_number_PK                 PRIMARY KEY (sku, manufacturer_number),  
    CONSTRAINT product_item_number_AK                 UNIQUE      (manufacturer_number, item_number), -- In this context, ‘manufacturer_number’ and ‘item_number’ compose an AK. 
    CONSTRAINT product_item_number_TO_product_FK      FOREIGN KEY (sku)
        REFERENCES product (sku),  
    CONSTRAINT product_item_number_TO_manufacturer_FK FOREIGN KEY (manufacturer_number) 
        REFERENCES manufacturer (manufacturer_number)  
);

Đã thử nghiệm trên PostgreSQL 11 trong db <> fiddle này .


Cân nhắc cấp độ vật lý

Chúng tôi đã không thảo luận về loại và kích thước chính xác của product.skucột nhưng, nếu đó là số lượng lớn về mặt byte, thì nó có thể làm giảm tốc độ truy xuất dữ liệu của hệ thống của bạn đối với các khía cạnh của mức độ trừu tượng hóa, được liên kết với, ví dụ, kích thước của các chỉ mục và không gian đĩa sử dụng.

Theo cách này, bạn có thể muốn đánh giá sự kết hợp của cột INTEGER có thể cung cấp phản hồi nhanh hơn so với một văn bản có thể nặng nề của một văn bản, tất cả phụ thuộc vào các tính năng chính xác của các cột được so sánh. Nó cũng có thể là product_number, như mong đợi, sẽ đại diện cho một giá trị số trong một chuỗi đứng cho tập hợp được ghi lại products.

Một sắp xếp kho lưu trữ kết hợp yếu tố mới này là một trong đó:

CREATE TABLE product ( 
    product_number INTEGER NOT NULL,
    sku            TEXT    NOT NULL, 
    name           TEXT    NOT NULL, 
    price          NUMERIC NOT NULL, 
    quantity       NUMERIC NOT NULL,
    --
    CONSTRAINT product_PK        PRIMARY KEY (sku), 
    CONSTRAINT product_AK        UNIQUE      (name), -- AK. 
    CONSTRAINT valid_price_CK    CHECK       (price > 0),
    CONSTRAINT valid_quantity_CK CHECK       (quantity > 0)
); 

CREATE TABLE product_item_number 
( 
    product_number INTEGER NOT NULL,
    item_number    TEXT    NOT NULL,
    --
    CONSTRAINT product_item_number_PK            PRIMARY KEY (product_number),  
    CONSTRAINT product_item_number_AK            UNIQUE      (item_number), -- AK.
    CONSTRAINT product_item_number_TO_product_FK FOREIGN KEY (product_number)
       REFERENCES product (product_number)   
);

Tôi đặc biệt khuyên bạn nên thực hiện các phiên kiểm tra đáng kể với tải dữ liệu đáng kể để quyết định khóa nào thuận tiện hơn khi nói tiếng Tây Ban Nha, luôn luôn tính đến các tính năng cơ sở dữ liệu tổng thể (số cột của tất cả các bảng, loại và kích cỡ của các cột, các ràng buộc và các chỉ mục cơ bản, v.v.).


Kịch bản tương tự

Môi trường kinh doanh quan tâm của bạn thể hiện sự tương đồng nhất định với kịch bản được xử lý trong các bài đăng này , vì vậy bạn có thể thấy sự liên quan của một số điểm được thảo luận.


1
Xin chào @MDCCL, bản sửa đổi của bạn rất sáng sủa, đặc biệt là gợi ý mà tôi xem xét sử dụng các phím tổng hợp. Cảm ơn bạn đã giải thích có chủ ý.
Harley

Xin chào, @Harley, đó là niềm vui của tôi. Nếu có những khía cạnh bạn muốn điều trị, chỉ cần cho tôi biết. Chúc mừng.
MDCCL

3

Nếu thuộc tính của bạn item_numberlà duy nhất, bạn có thể để nó trong bảng gốc của mình ngay cả trong trường hợp nó có thể có giá trị null. Trong thực tế, hướng dẫn PostgreSQL nói:

Đối với mục đích của một ràng buộc duy nhất, các giá trị null không được coi là bằng nhau.

Vì vậy, đây có thể là giải pháp đúng:

CREATE TABLE product (
   sku            text PRIMARY KEY,
   name           text UNIQUE NOT NULL,
   price          numeric NOT NULL CHECK (price > 0),
   quantity       numeric NOT NULL CHECK (quantity > 0),
   item_number    text UNIQUE
);

hiệu quả hơn giải pháp B và lập trình đơn giản hơn giải pháp C.

Lưu ý rằng giải pháp này được chuẩn hóa, do đó bạn không có bất kỳ sự dư thừa nào, bạn cũng không có bất thường chèn / xóa.

Thêm vào

Để một mối quan hệ được chính thức trong Boyce Codd Form Form (nghiêm ngặt hơn so với Form thường thứ ba), đối với mỗi phụ thuộc, định thức phải là một khóa (siêu). Nhưng lưu ý đầu tiên rằng lý thuyết chuẩn hóa thường không xử lý các giá trị null. Ví dụ, hãy xem cuốn sách của Elmasri, Navedit, cơ bản của các hệ thống cơ sở dữ liệu ". Phiên bản thứ 6, 2010:

Vẫn chưa có lý thuyết thiết kế quan hệ hoàn toàn thỏa đáng bao gồm các giá trị NULL

Trong trường hợp này, chúng tôi có ít nhất sự phụ thuộc:

sku  name, price, quantity, item_number

và trên thực tế skulà một chìa khóa cho mối quan hệ.

Sau đó, giả sử rằng không có giá trị null, nếu bạn muốn item_numberlà duy nhất, tồn tại một phụ thuộc khác:

item_number  sku, name, price, quantity

và vì vậy, item_numberlà một chìa khóa khác.

Trong mối quan hệ này, không có sự phụ thuộc chức năng nào khác, một phần từ những người xuất phát từ hai điều này và cả hai sự phụ thuộc này đều không vi phạm BCNF (cả hai yếu tố quyết định đều là khóa). Vì vậy, mối quan hệ là ở dạng bình thường Boyce Codd.

Mặt khác, nếu bạn cho rằng item_numbercó thể có giá trị null, bạn có thể giả sử rằng phụ thuộc thứ hai không giữ được, do đó mối quan hệ lại xuất hiện trong BCNF.


1
Cảm ơn, Renzo. Tôi đánh giá cao sự hiểu biết của bạn. Tôi đã đọc phần đó của hướng dẫn. Tôi cũng đã đọc trang bìa "Mô hình hóa dữ liệu và thiết kế cơ sở dữ liệu" của Umanath và Scamell, nhưng không có tình huống nào như thế này được giải quyết. Đối với mục đích học tập, giả sử item_number luôn xác định chức năng mọi thuộc tính khác của sản phẩm (khi item_number tồn tại). Nếu chúng tôi cho phép nó là null, thì item_number không thể là khóa ứng viên. Như vậy, đó là một thuộc tính không chính và vì vậy mối quan hệ của bạn vi phạm hình thức bình thường thứ 3.
Harley

1
Tôi không nhất thiết phải đề xuất sự bất thường sẽ xảy ra. Tôi cần một chút thời gian để suy nghĩ về điều đó. Thay vào đó, tôi cho rằng bảng sản phẩm trong ví dụ của bạn không được chuẩn hóa thành 3NF. Tôi có thể sai, tất nhiên. Có lẽ đây là tất cả học tập. Những hiểu biết sâu sắc hơn từ bạn sẽ được chào đón nhất. Chúc mừng.
Harley

@Harley, tôi đã thêm vào câu trả lời một lời giải thích chi tiết hơn trong khi mối quan hệ được chuẩn hóa.
Renzo
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.