2009-04-17 28 views
18

Làm cách nào để triển khai trường liệt kê trong cơ sở dữ liệu không hỗ trợ liệt kê? (ví dụ: SQLite)Làm cách nào để xử lý các liệt kê mà không có các trường enum trong cơ sở dữ liệu?

Các trường cần phải dễ dàng tìm kiếm được với "field =?" vì vậy việc sử dụng bất kỳ loại dữ liệu tuần tự hóa nào là một ý tưởng tồi.

+0

Nếu đây là bản sao, vui lòng trở nên tốt đẹp. Tôi đã tìm câu trả lời trên StackOverflow trước khi tôi hỏi. – epochwolf

Trả lời

49

Sử dụng khóa ngoài để bảng tra cứu là cách tiếp cận tôi sử dụng. Trong thực tế, tôi sử dụng điều này ngay cả khi tôi sử dụng cơ sở dữ liệu hỗ trợ ENUM (ví dụ: MySQL).

Để đơn giản, tôi có thể bỏ qua "id" cho bảng tra cứu và chỉ sử dụng giá trị thực tế tôi cần trong bảng chính làm khóa chính của bảng tra cứu. Bằng cách đó bạn không cần phải tham gia để có được giá trị.

CREATE TABLE BugStatus (
    status   VARCHAR(20) PRIMARY KEY 
); 

INSERT INTO BugStatus (status) VALUES ('NEW'), ('OPEN'), ('FIXED'); 

CREATE TABLE Bugs (
    bug_id   SERIAL PRIMARY KEY, 
    summary   VARCHAR(80), 
    ... 
    status   VARCHAR(20) NOT NULL DEFAULT 'NEW', 
    FOREIGN KEY (status) REFERENCES BugStatus(status) 
); 

Phải thừa nhận rằng, tàng trữ chuỗi mất nhiều không gian hơn việc thực hiện các ENUM MySQL, nhưng trừ khi các bảng trong câu hỏi có hàng triệu hàng, nó hầu như không quan trọng.

lợi thế khác của các bảng tra cứu được rằng bạn có thể thêm hoặc loại bỏ một giá trị từ danh sách với một đơn giản INSERT hoặc DELETE, trong khi với ENUM bạn phải sử dụng ALTER TABLE để xác định lại danh sách.

Cũng thử truy vấn danh sách giá trị được phép hiện tại trong một số ENUM, ví dụ để điền danh sách lựa chọn trong giao diện người dùng của bạn. Đó là một khó chịu lớn! Với bảng tra cứu, thật dễ dàng: SELECT status from BugStatus.

Ngoài ra, bạn có thể thêm các cột thuộc tính khác vào bảng tra cứu nếu cần (ví dụ: để đánh dấu lựa chọn chỉ có sẵn cho quản trị viên). Trong một số ENUM, bạn không thể chú thích các mục nhập; chúng chỉ là những giá trị đơn giản.

Một tùy chọn khác bên cạnh một bảng tra cứu sẽ được sử dụng CHECK chế (được cung cấp cơ sở dữ liệu hỗ trợ họ - MySQL không):

CREATE TABLE Bugs (
    bug_id   SERIAL PRIMARY KEY, 
    summary   VARCHAR(80), 
    ... 
    status   VARCHAR(20) NOT NULL 
    CHECK (status IN ('NEW', 'OPEN', 'FIXED')) 
); 

Nhưng sử dụng này là một hạn chế CHECK bị so với cùng bất lợi là ENUM: khó thay đổi danh sách giá trị mà không cần ALTER TABLE, khó truy vấn danh sách các giá trị được phép, khó chú thích các giá trị.

PS: toán tử so sánh bình đẳng trong SQL là một =. Các đôi == không có ý nghĩa trong SQL.

+0

Cảm ơn điều = = == :) Đã một thời gian kể từ khi tôi sử dụng SQL trực tiếp. – epochwolf

+0

câu trả lời hay, +1 từ tôi. – Brann

+0

Một câu hỏi cũ, nhưng câu trả lời tuyệt vời. Bỏ phiếu lên. –

-1

Tôi sẽ sử dụng một varchar. Đây không phải là một lựa chọn cho bạn?

+0

Sử dụng VARCHAR sẽ dẫn đến dữ liệu không chuẩn hóa. Nếu bạn muốn thay đổi tên của giá trị enum, nó yêu cầu cập nhật trên toàn bộ bảng, thay vì chỉ thay đổi một hàng trong bảng tham chiếu. –

1

Bạn về cơ bản có hai lựa chọn:

  • sử dụng một trường số nguyên

  • sử dụng một lĩnh vực varchar

Cá nhân tôi sẽ ủng hộ việc sử dụng varchars, bởi vì bạn đã thắng' t phá vỡ bất cứ điều gì nếu bạn thay đổi enum của bạn + các lĩnh vực được con người có thể đọc được, nhưng ints có một số pro tốt, cụ thể là hiệu suất (kích thước của dữ liệu là một ví dụ rõ ràng)

2

Để hạn chế các giá trị có thể, tôi sẽ sử dụng khóa ngoài cho bảng chứa các mục điều tra.

Nếu bạn không muốn THAM GIA thực hiện tìm kiếm của mình thì hãy tạo khóa là varchar nếu JOINS không phải là vấn đề, sau đó tạo khóa INT và không tham gia trừ khi bạn cần tìm kiếm trên trường đó.

Lưu ý rằng việc đặt bảng liệt kê trong DB ngăn cản việc kiểm tra thời gian biên dịch các giá trị trong mã của bạn (trừ khi bạn sao y liệt kê mã.) Tôi đã nhận thấy đây là một mặt giảm lớn.

0

Đây là những gì tôi đã làm gần đây

Trong ngủ đông của tôi ánh xạ POJO- Tôi giữ các loại thành viên như String và nó là VARCHAR trong cơ sở dữ liệu.

Các setter cho điều này mất một enum Có một setter mà mất STRING- nhưng đây là tư nhân (hoặc bạn có thể lập bản đồ directly- lĩnh vực nếu đó là những gì bạn thích.)

Bây giờ thực tế tôi đang sử dụng Chuỗi được đóng gói từ tất cả. Đối với phần còn lại của ứng dụng, các đối tượng miền của tôi sử dụng enum. Và theo như cơ sở dữ liệu có liên quan, tôi đang sử dụng String.

Nếu tôi bỏ lỡ câu hỏi của bạn- Tôi xin lỗi.

+0

Điều này có ý nghĩa. Ruby on Rails sẽ cho phép hành vi tương tự với các xác nhận hợp lệ như một phần thưởng. – epochwolf

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