Tôi có thể có nhiều khóa chính trong một bảng không?


Câu trả lời:


559

Bảng có thể có Khóa chính tổng hợp là khóa chính được tạo từ hai hoặc nhiều cột. Ví dụ:

CREATE TABLE userdata (
  userid INT,
  userdataid INT,
  info char(200),
  primary key (userid, userdataid)
);

Cập nhật: Đây là một liên kết với một mô tả chi tiết hơn về các khóa chính tổng hợp.


2
Trong ví dụ này, BOTH userid và userdataid là cần thiết để xác định / tìm một hàng duy nhất. Không chắc ý định của OP là gì, nhưng tôi đến đây để xem liệu tôi có thể xác định duy nhất một hàng với một trong các bộ khóa hay không. Chẳng hạn, tôi muốn xác định một người dùng duy nhất có tên người dùng HOẶC tên người dùng mà không cần cả hai. Tôi đoán câu trả lời của các chỉ số duy nhất của RB sẽ thực hiện thủ thuật đó.
Burrito

1
@Benitok Như đã đề cập trong câu trả lời của RB. , Bạn có thể sử dụng Chỉ mục duy nhất để làm những gì bạn đang tìm kiếm (một cột duy nhất, được lập chỉ mục độc lập với các cột được lập chỉ mục, duy nhất khác trên cùng một bảng). Hãy chắc chắn tham khảo hương vị cụ thể của hướng dẫn sử dụng SQL để biết chi tiết về cú pháp ngôn ngữ chính xác được sử dụng.
4 giờ sáng

195

Bạn chỉ có thể có một khóa chính, nhưng bạn có thể có nhiều cột trong khóa chính của mình.

Bạn cũng có thể có các Chỉ mục duy nhất trên bảng của mình, nó sẽ hoạt động giống như một khóa chính ở chỗ chúng sẽ thực thi các giá trị duy nhất và sẽ tăng tốc truy vấn các giá trị đó.


39

Một bảng có thể có nhiều khóa ứng cử viên. Mỗi khóa ứng cử viên là một cột hoặc một tập hợp các cột là ĐỘC ĐÁO, được ghép lại với nhau và cũng KHÔNG PHẢI. Do đó, việc chỉ định giá trị cho tất cả các cột của bất kỳ khóa ứng cử viên nào là đủ để xác định rằng có một hàng đáp ứng tiêu chí hoặc không có hàng nào cả.

Khóa ứng viên là một khái niệm cơ bản trong mô hình dữ liệu quan hệ.

Đó là thông lệ, nếu có nhiều khóa trong một bảng, để chỉ định một trong các khóa ứng viên làm khóa chính. Đó cũng là cách phổ biến để tạo bất kỳ khóa ngoại nào vào bảng để tham chiếu khóa chính, thay vì bất kỳ khóa ứng cử viên nào khác.

Tôi khuyên bạn nên thực hành những điều này, nhưng không có gì trong mô hình quan hệ yêu cầu chọn khóa chính trong số các khóa ứng cử viên.


5
Đã đồng ý. Tất cả các khóa đều bằng nhau (không có khóa nào là 'chính') trong mô hình logic. Sự lựa chọn của khóa nào trong việc triển khai thực tế có được chỉ định PRIMARY KEY là tùy ý và phụ thuộc vào nhà cung cấp / sản phẩm.
onedaywhen

3
Tôi muốn nói rằng nó phụ thuộc vào thiết kế cơ sở dữ liệu.
Walter Mitty

Tôi vừa gặp một trường hợp sử dụng trong trường hợp này là bắt buộc. Tôi có một bảng sẽ được tạo / quản lý bởi Entity Framework - hiện tại tôi có thể thu thập không hỗ trợ các ràng buộc tổng hợp duy nhất không phải là khóa chính hiện tại. Tuy nhiên, nó không hỗ trợ Khóa chính tổng hợp. Dữ liệu cũng sẽ được liên kết với một hệ thống cơ sở dữ liệu từ xa không hỗ trợ các khóa tổng hợp. Tôi đã bắt đầu tạo một PK tổng hợp trong EF nhưng cũng thêm một cột GUID không thể rỗng mà hệ thống khác có thể sử dụng để nhận dạng duy nhất chống lại.
Chris Nevill

2
Chris, tôi đã nói rằng mô hình quan hệ không yêu cầu khóa chính. Tôi đã không nói bất cứ điều gì về việc một số công cụ có thể yêu cầu họ. Nhưng tôi có quan điểm của bạn.
Walter Mitty

Tôi nghĩ rằng có một yêu cầu rằng PK là tối thiểu, nghĩa là sử dụng số lượng cột ít nhất để xác định duy nhất mỗi bản ghi.
gary

14

Đây là câu trả lời cho cả câu hỏi chính và cho câu hỏi của @ Kalmi về

Điều gì sẽ là điểm có nhiều cột tạo tự động?

Mã này dưới đây có một khóa chính tổng hợp. Một trong những cột của nó được tăng tự động. Điều này sẽ chỉ hoạt động trong MyISAM. InnoDB sẽ tạo ra lỗi " ERROR 1075 (42000): Định nghĩa bảng không chính xác; chỉ có thể có một cột tự động và nó phải được xác định là khóa ".

DROP TABLE IF EXISTS `test`.`animals`;
CREATE TABLE  `test`.`animals` (
  `grp` char(30) NOT NULL,
  `id` mediumint(9) NOT NULL AUTO_INCREMENT,
  `name` char(30) NOT NULL,
  PRIMARY KEY (`grp`,`id`)
) ENGINE=MyISAM;

INSERT INTO animals (grp,name) VALUES
    ('mammal','dog'),('mammal','cat'),
    ('bird','penguin'),('fish','lax'),('mammal','whale'),
    ('bird','ostrich');

SELECT * FROM animals ORDER BY grp,id;

Which returns:

+--------+----+---------+
| grp    | id | name    |
+--------+----+---------+
| fish   |  1 | lax     |
| mammal |  1 | dog     |
| mammal |  2 | cat     |
| mammal |  3 | whale   |
| bird   |  1 | penguin |
| bird   |  2 | ostrich |
+--------+----+---------+

2
Điều này hoạt động nếu bạn chỉ định cột tăng tự động trước trong định nghĩa khóa chính. (Có lẽ điều này đã thay đổi, tôi mới thử nó vào 5.6)
CTarczon

11

(Đã nghiên cứu những điều này, rất nhiều)

Các khóa ứng cử viên - Một tổ hợp cột tối thiểu được yêu cầu để xác định duy nhất một hàng của bảng.
Phím ghép - 2 cột trở lên.

  • Nhiều khóa Ứng viên có thể tồn tại trong một bảng.
    • Khóa chính - Chỉ một trong số các khóa ứng cử viên được chúng tôi chọn
    • Khóa thay thế - Tất cả các khóa ứng cử viên khác
      • Cả khóa chính và khóa thay thế đều có thể là phím Compound

Nguồn:
https://en.wikipedia.org/wiki/Superkey
https://en.wikipedia.org/wiki/Candidate_key
https://en.wikipedia.org/wiki/Primary_key
https://en.wikipedia.org / wiki / Compound_key


6

Theo ghi nhận của những người khác, có thể có các khóa chính nhiều cột. Tuy nhiên, cần lưu ý rằng nếu bạn có một số phụ thuộc chức năng không được giới thiệu bởi một khóa, bạn nên xem xét bình thường hóa mối quan hệ của mình.

Thí dụ:

Person(id, name, email, street, zip_code, area)

Có thể có một sự phụ thuộc chức năng giữa id -> name,email, street, zip_code and area Nhưng thường a zip_codeđược liên kết với a areavà do đó có một sự phụ thuộc chức năng bên trong giữa zip_code -> area.

Do đó, người ta có thể xem xét tách nó vào một bảng khác:

Person(id, name, email, street, zip_code)
Area(zip_code, name)

Vì vậy, nó phù hợp với hình thức bình thường thứ ba .


6

Khóa chính là ký hiệu rất đáng tiếc, vì ý nghĩa của "Chính" và mối liên hệ tiềm thức trong hệ quả với Mô hình logic. Vì vậy, tôi tránh sử dụng nó. Thay vào đó, tôi đề cập đến Khóa thay thế của Mô hình vật lý và Khóa tự nhiên của Mô hình logic.

Điều quan trọng là Mô hình logic cho mọi Thực thể phải có ít nhất một bộ "thuộc tính kinh doanh" bao gồm Khóa cho thực thể. Boyce, Codd, Date et al đề cập đến những điều này trong Mô hình quan hệ là Khóa ứng viên. Sau đó, khi chúng tôi xây dựng các bảng cho các Thực thể này, Khóa Ứng viên của chúng trở thành Khóa tự nhiên trong các bảng đó. Chỉ thông qua các Khóa tự nhiên đó, người dùng mới có thể xác định duy nhất các hàng trong bảng; vì các khóa thay thế phải luôn được ẩn khỏi người dùng. Điều này là do Khóa Surrogate không có ý nghĩa kinh doanh.

Tuy nhiên, Mô hình vật lý cho các bảng của chúng tôi trong nhiều trường hợp sẽ không hiệu quả nếu không có Khóa thay thế. Hãy nhớ lại rằng các cột không được bao phủ cho một chỉ mục không được phân cụm chỉ có thể được tìm thấy (nói chung) thông qua Tra cứu khóa vào chỉ mục được phân cụm (bỏ qua các bảng được triển khai dưới dạng heap trong giây lát). Khi (các) Khóa tự nhiên khả dụng của chúng tôi rộng, (1) này sẽ mở rộng chiều rộng của các nút lá không phân cụm của chúng tôi, tăng yêu cầu lưu trữ và truy cập đọc để tìm kiếm và quét chỉ mục không phân cụm đó; và (2) giảm quạt ra khỏi chỉ mục được nhóm của chúng tôi tăng chiều cao chỉ mục và kích thước chỉ mục, một lần nữa tăng yêu cầu đọc và lưu trữ cho các chỉ mục được nhóm của chúng tôi; và (3) tăng yêu cầu bộ đệm cho các chỉ mục được nhóm của chúng tôi. đuổi các chỉ mục và dữ liệu khác ra khỏi bộ đệm.

Đây là nơi một Khóa thay thế nhỏ, được chỉ định cho RDBMS là "Khóa chính" chứng tỏ có lợi. Khi được đặt làm khóa phân cụm, để được sử dụng cho tra cứu khóa vào chỉ mục được phân cụm từ các chỉ mục không được phân cụm và tra cứu khóa ngoại từ các bảng có liên quan, tất cả các nhược điểm này sẽ biến mất. Quạt tăng chỉ số cụm của chúng tôi tăng trở lại để giảm chiều cao và kích thước chỉ mục cụm, giảm tải bộ đệm cho các chỉ mục được nhóm của chúng tôi, giảm đọc khi truy cập dữ liệu thông qua bất kỳ cơ chế nào (cho dù quét chỉ mục, tìm kiếm chỉ mục, tra cứu khóa không phân cụm hoặc tra cứu khóa ngoài) và giảm yêu cầu lưu trữ cho cả các chỉ mục được nhóm và không bao gồm các bảng của chúng tôi.

Lưu ý rằng những lợi ích này chỉ xảy ra khi khóa thay thế vừa nhỏ vừa là khóa phân cụm. Nếu GUID được sử dụng làm khóa phân cụm, tình huống thường sẽ tồi tệ hơn nếu sử dụng Khóa tự nhiên nhỏ nhất có sẵn. Nếu bảng được tổ chức dưới dạng heap thì RowID 8 byte (heap) sẽ được sử dụng để tra cứu khóa, tốt hơn GUID 16 byte nhưng ít hiệu suất hơn số nguyên 4 byte.

Nếu GUID phải được sử dụng do các ràng buộc kinh doanh thì việc tìm kiếm khóa phân cụm tốt hơn là đáng giá. Ví dụ, nếu một số nhận dạng trang web nhỏ và "số thứ tự trang web" 4 byte là khả thi thì thiết kế đó có thể cho hiệu suất tốt hơn GUID là Khóa thay thế.

Nếu hậu quả của một đống (có thể là băm tham gia) làm cho lưu trữ ưu tiên thì chi phí của khóa phân cụm rộng hơn cần được cân bằng trong phân tích đánh đổi.

Xem xét ví dụ này ::

ALTER TABLE Persons
ADD CONSTRAINT pk_PersonID PRIMARY KEY (P_Id,LastName)

trong đó tuple " (P_Id, LastName) " yêu cầu một ràng buộc duy nhất và có thể là một LastName Unicode dài cộng với một số nguyên 4 byte, nên (1) sẽ thực thi một cách khai báo ràng buộc này là " THÊM CONSTRAINT pk_PersonID UNIITE NON , LastName) "và (2) khai báo riêng một Khóa Surrogate nhỏ là" Khóa chính "của một chỉ mục được nhóm. Điều đáng chú ý là Anita chỉ có thể muốn thêm LastName vào ràng buộc này để tạo ra một trường được bao phủ, không cần thiết trong một chỉ mục được nhóm vì TẤT CẢ các trường được bao phủ bởi nó.

Khả năng trong SQL Server chỉ định Khóa chính là không bao gồm là một trường hợp lịch sử đáng tiếc, do sự kết hợp của ý nghĩa "khóa tự nhiên hoặc khóa ứng cử viên" (từ Mô hình logic) với nghĩa là "khóa tra cứu trong kho" Mô hình. Tôi hiểu rằng ban đầu, SQL Server SYBASE luôn sử dụng RowID 4 byte, cho dù là một heap hay một chỉ mục được nhóm, như là "khóa tra cứu trong lưu trữ" từ Mô hình vật lý.


3
Bạn có thể vui lòng dịch nó sang tiếng Anh!
Jasir

3

Một số người sử dụng thuật ngữ "khóa chính" có nghĩa chính xác là một cột số nguyên có các giá trị được tạo bởi một số cơ chế tự động. Ví dụ: AUTO_INCREMENTtrong MySQL hoặc IDENTITYMicrosoft SQL Server. Bạn đang sử dụng khóa chính theo nghĩa này?

Nếu vậy, câu trả lời phụ thuộc vào thương hiệu cơ sở dữ liệu bạn đang sử dụng. Trong MySQL, bạn không thể làm điều này, bạn gặp lỗi:

mysql> create table foo (
  id int primary key auto_increment, 
  id2 int auto_increment
);
ERROR 1075 (42000): Incorrect table definition; 
there can be only one auto column and it must be defined as a key

Trong một số thương hiệu cơ sở dữ liệu khác, bạn có thể xác định nhiều hơn một cột tạo tự động trong một bảng.


5
Điều gì sẽ là điểm có nhiều cột tạo tự động?
Tarnay Kálmán

Tôi không có trường hợp sử dụng trong đầu, nhưng nếu có nhu cầu, một số thương hiệu cơ sở dữ liệu sẽ hỗ trợ điều này và một số thì không. Đó là tất cả những gì tôi đang nói.
Bill Karwin

1
Đây là một trường hợp: trong bảng đơn hàng, tôi có cả ID (tự động tăng) và ID bên ngoài (chuỗi giống như hàm băm), cả hai phải là duy nhất để theo lý thuyết bạn có thể nói rằng cả hai đều là "chính". tất nhiên điều này có thể được thực hiện với một chỉ số duy nhất thứ cấp nhưng vẫn là trường hợp hợp pháp (IMHO)
Nir

2

Có hai khóa chính cùng một lúc, là không thể. Nhưng (giả sử rằng bạn chưa làm hỏng trường hợp bằng khóa tổng hợp), có thể điều bạn có thể cần là làm cho một thuộc tính duy nhất.

CREATE t1(
c1 int NOT NULL,
c2 int NOT NULL UNIQUE,
...,
PRIMARY KEY (c1)
);

Tuy nhiên, lưu ý rằng trong cơ sở dữ liệu quan hệ, 'siêu khóa' là tập hợp con của các thuộc tính xác định duy nhất một tuple hoặc hàng trong bảng. 'Khóa' là một 'siêu khóa' có thuộc tính bổ sung loại bỏ bất kỳ thuộc tính nào khỏi khóa, làm cho khóa đó không còn là 'siêu khóa' (hay đơn giản là 'khóa' là một siêu khóa tối thiểu). Nếu có nhiều khóa, tất cả chúng đều là khóa ứng cử viên. Chúng tôi chọn một trong các khóa ứng cử viên làm khóa chính. Đó là lý do tại sao nói về nhiều khóa chính cho một mối quan hệ hoặc bảng đang là một xung đột.


Wikipedia không có định nghĩa cho 'khóa'. Ngoài ra, việc "xóa bất kỳ thuộc tính nào khỏi khóa, làm cho khóa đó không còn là" siêu khóa "" không có ý nghĩa gì đối với tôi, vì khi xóa một thuộc tính khỏi siêu khóa vẫn có thể là siêu khóa.
Manohar Reddy Poreddy

@ManoharReddyPoreddy Có, trong trường hợp đó, bộ thuộc tính của bạn không phải là 'khóa' mà là 'siêu khóa'. Ý tôi là nếu một tập hợp các thuộc tính là 'khóa', thì tập hợp đó phải ở mức tối thiểu hoặc tập hợp đó phải có một thuộc tính bổ sung loại bỏ bất kỳ thuộc tính nào khỏi tập hợp làm cho tập kết quả không phải là 'siêu khóa'.
Rusiru Adithya Samarasinghe

Có vẻ như, ý nghĩa thực sự của bạn về 'khóa' là Candidate_key ( en.wikipedia.org/wiki/Candidate_key ), có lẽ nên được đề cập như vậy.
Manohar Reddy Poreddy

@ManoharReddyPoreddy Có tôi đã đề cập đến nó trong câu trả lời của tôi. "Nếu có nhiều khóa, tất cả chúng đều là khóa ứng viên". Dù sao cũng cảm ơn bạn đã xem xét.
Rusiru Adithya Samarasinghe

1. Khi bạn đề cập "Nếu có nhiều khóa hơn, tất cả chúng đều là khóa ứng viên", ... Ý của bạn là khác / khác, chúng không phải là khóa ứng viên? ... 2. Phần khác ở đâu? ... Chúng ta có cùng một trang không?
Manohar Reddy Poreddy

1

Khóa chính là khóa xác định duy nhất một bản ghi và được sử dụng trong tất cả các chỉ mục. Đây là lý do tại sao bạn không thể có nhiều hơn một. Nó cũng thường là khóa được sử dụng để tham gia vào các bảng con nhưng đây không phải là một yêu cầu. Mục đích thực sự của PK là đảm bảo rằng một cái gì đó cho phép bạn xác định duy nhất một bản ghi để thay đổi dữ liệu ảnh hưởng đến bản ghi chính xác và để có thể tạo các chỉ mục.

Tuy nhiên, bạn có thể đặt nhiều trường trong một khóa chính (PK tổng hợp). Điều này sẽ làm cho các phép nối của bạn chậm hơn (đặc biệt nếu chúng là các trường kiểu chuỗi lớn hơn) và các chỉ mục của bạn lớn hơn nhưng nó có thể loại bỏ sự cần thiết phải tham gia trong một số bảng con, theo như hiệu suất và thiết kế, hãy đưa nó vào trường hợp trường hợp cơ sở. Khi bạn làm điều này, mỗi lĩnh vực tự nó không phải là duy nhất, nhưng sự kết hợp của chúng là. Nếu một hoặc nhiều trường trong khóa tổng hợp cũng phải là duy nhất, thì bạn cần một chỉ mục duy nhất trên đó. Có khả năng mặc dù nếu một lĩnh vực là duy nhất, đây là một ứng cử viên tốt hơn cho PK.

Bây giờ, đôi khi, bạn có nhiều hơn một ứng cử viên cho PK. Trong trường hợp này, bạn chọn một khóa làm PK hoặc sử dụng khóa thay thế (cá nhân tôi thích khóa thay thế cho trường hợp này). Và (điều này rất quan trọng!) Bạn thêm các chỉ mục duy nhất vào mỗi khóa ứng cử viên không được chọn làm PK. Nếu dữ liệu cần là duy nhất, nó cần một chỉ mục duy nhất cho dù đó là PK hay không. Đây là một vấn đề toàn vẹn dữ liệu. (Lưu ý điều này cũng đúng bất cứ khi nào bạn sử dụng khóa thay thế; mọi người gặp rắc rối với các khóa thay thế vì họ quên tạo các chỉ mục duy nhất trên các khóa ứng viên.)

Đôi khi bạn muốn có nhiều hơn một khóa thay thế (thường là PK nếu bạn có chúng). Trong trường hợp này, những gì bạn muốn không phải là PK nhiều hơn, đó là nhiều trường hơn với các khóa được tạo tự động. Hầu hết các DB không cho phép điều này, nhưng có nhiều cách để khắc phục nó. Trước tiên hãy xem xét trường thứ hai có thể được tính dựa trên khóa được tạo tự động đầu tiên (ví dụ Field1 * -1) hoặc có lẽ nhu cầu về khóa tự động thứ hai thực sự có nghĩa là bạn nên tạo một bảng có liên quan. Các bảng liên quan có thể trong mối quan hệ một-một. Bạn sẽ thực thi điều đó bằng cách thêm PK từ bảng cha vào bảng con và sau đó thêm trường được tạo tự động mới vào bảng và sau đó bất kỳ trường nào phù hợp với bảng này. Sau đó chọn một trong hai khóa làm PK và đặt một chỉ mục duy nhất ở bên kia (trường được tạo tự động không phải là PK). Và đảm bảo thêm FK vào trường trong bảng cha. Nói chung nếu bạn không có các trường bổ sung cho bảng con, bạn cần kiểm tra lý do tại sao bạn nghĩ rằng bạn cần hai trường tự phát.


0

Câu trả lời kỹ thuật tốt đã được đưa ra theo cách tốt hơn tôi có thể làm. Tôi chỉ có thể thêm vào chủ đề này:

Nếu bạn muốn một cái gì đó không được phép / chấp nhận, đó là lý do tốt để lùi lại.

  1. Hiểu cốt lõi của lý do tại sao nó không được chấp nhận.
  2. Đào sâu hơn trong tài liệu / bài báo tạp chí / web và vv
  3. Phân tích / xem xét thiết kế hiện tại và điểm sai sót lớn.
  4. Xem xét và kiểm tra từng bước trong quá trình thiết kế mới.
  5. Luôn mong đợi và cố gắng tạo ra giải pháp thích ứng.

Hy vọng nó sẽ giúp được ai đó.


1
lời khuyên chung chung (mặc dù hữu ích), không phải là một câu trả lời cho câu hỏi cụ thể.
Bradford Needham

-3

Có, có thể có trong SQL, nhưng chúng tôi không thể đặt nhiều hơn một khóa chính trong MsAccess. Sau đó, tôi không biết về các cơ sở dữ liệu khác.

CREATE TABLE CHAPTER (
    BOOK_ISBN VARCHAR(50) NOT NULL,
    IDX INT NOT NULL,
    TITLE VARCHAR(100) NOT NULL,
    NUM_OF_PAGES INT,
    PRIMARY KEY (BOOK_ISBN, IDX)
);

Một bảng SQL chỉ có thể có một PK.
philipxy
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.