2012-09-10 47 views

Trả lời

18

Mặc dù bạn không thể truyền enum thành số nguyên như Catcall giải thích, bạn có thể sử dụng bảng danh mục hệ thống pg_enum tương thích với PostgreSQL cụ thể và không phiên bản để có được đại diện thứ tự.

regress=# CREATE TYPE happiness AS ENUM ('happy', 'very happy', 'ecstatic'); 

regress=# select enumsortorder, enumlabel from pg_catalog.pg_enum 
regress-# WHERE enumtypid = 'happiness'::regtype ORDER BY enumsortorder; 
enumsortorder | enumlabel 
---------------+------------ 
      1 | happy 
      2 | very happy 
      3 | ecstatic 
(3 rows) 

Điều này có vẻ dễ dàng, nhưng không phải vậy. Quan sát:

regress=# ALTER TYPE happiness ADD VALUE 'sad' BEFORE 'happy'; 
regress=# ALTER TYPE happiness ADD VALUE 'miserable' BEFORE 'very happy'; 
regress=# SELECT * FROM pg_enum ; 
enumtypid | enumsortorder | enumlabel 
-----------+---------------+------------ 
    185300 |    1 | happy 
    185300 |    2 | very happy 
    185300 |    3 | ecstatic 
    185300 |    0 | sad 
    185300 |   1.5 | miserable 
(5 rows) 

Từ đây bạn có thể thấy rằng enumsortorder cung cấp thứ tự, nhưng không cố định 'khoảng cách'. Nếu hỗ trợ cho việc loại bỏ các giá trị từ enums được thêm vào, nó sẽ có khả năng tạo ra 'lỗ' trong trình tự, quá.

Để có được vị trí enum, bạn sẽ cần sử dụng chức năng cửa sổ row_number() để nhận đơn đặt hàng và pg_typeof để nhận số oid (regtype) của loại enum. Bạn cần điều này để đảm bảo rằng bạn trả lại đúng thứ tự khi có nhiều enums với cùng một nhãn.

Chức năng này không được công việc:

CREATE OR REPLACE FUNCTION enum_to_position(anyenum) RETURNS integer AS $$ 
SELECT enumpos::integer FROM (
     SELECT row_number() OVER (order by enumsortorder) AS enumpos, 
       enumsortorder, 
       enumlabel 
     FROM pg_catalog.pg_enum 
     WHERE enumtypid = pg_typeof($1) 
    ) enum_ordering 
    WHERE enumlabel = ($1::text); 
$$ LANGUAGE 'SQL' STABLE STRICT; 

Lưu ý:

  • Đó là STABLE không IMMUTABLE, bởi vì thêm (hoặc nếu hỗ trợ trong Thạc được sau bổ sung, loại bỏ) các giá trị từ enums sẽ thay đổi các chỉ số đặt hàng và phá vỡ dựa trên thứ tự; do đó
  • Bạn không thể sử dụng điều này trong biểu thức chỉ mục; và
  • Đó là STRICT vì nó sẽ trả về null cho một đầu vào vô

Bây giờ bạn có thể sử dụng chức năng này để CREATE CAST cho enums cụ thể để integer. Bạn không thể tạo một diễn viên chung cho tất cả các enums thành integer, vì không thể sử dụng loại giả anyenum cho các phôi. Ví dụ, nếu tôi muốn cho phép bản demo happiness được đúc để nguyên, tôi sẽ viết:

CREATE CAST (happiness AS integer) WITH FUNCTION enum_to_position(anyenum); 

sau đó tôi có thể thực hiện thành công:

regress=# SELECT ('happy'::happiness)::integer; 
int4 
------ 
    2 
(1 row) 

Lưu ý rằng đây có lẽ là một điên điều cần làm, không được hỗ trợ và rất có thể là một ý tưởng tồi tệ. Mã của bạn phải lưu ý rằng các giá trị thứ tự sẽ thay đổi khi bạn thêm hoặc (nếu sau này được hỗ trợ) xóa một giá trị khỏi enum.

Chỉ mục được tạo dựa trên dàn diễn viên này (chỉ có thể nếu hàm được định nghĩa bất biến) sẽ bắt đầu tạo ra kết quả điên và sai nếu bạn thay đổi định nghĩa của enum (ngoại trừ bằng cách thêm giá trị mới vào cuối) vì PostgreSQL tin bạn khi bạn nói một hàm là bất biến. Đừng làm thế.

3

Bạn không thể đúc một enum thành số nguyên.

Bạn có thể có thể viết số custom operator để trích xuất số được liên kết với giá trị, nhưng tôi thấy khó tin rằng điều đó đáng để gây rắc rối.

Nếu tôi cần loại thông tin đó, tôi đã xây dựng một bảng và đặt tham chiếu khóa ngoài cho nó thay vì sử dụng enum.

11

Bạn có thể thực hiện việc này thông qua việc lạm dụng thông minh chức năng enum_range().

Nếu bạn chuyển giá trị enum của bạn làm đối số thứ hai của hàm enum_range(), với NULL là giá trị đầu tiên, bạn sẽ nhận được một mảng với tất cả các giá trị mà enum có thể lấy đến điểm đó. Sau đó, bạn chỉ cần đếm chúng với array_length và bạn nhận được một số nguyên đại diện cho enum.

Đây là một ví dụ. Đây là enum của tôi:

content=# select enum_range(null::content_state); 
         enum_range       
-------------------------------------------------------------- 
{created,deleted,preview,draft,submitted,approved,published} 

Và đây là tôi tìm ra int cho "dự thảo" Giá trị:

content=# select array_length(enum_range(NULL, 'draft'::content_state), 1); 
array_length 
-------------- 
      4 

Nên biết trước: loại bỏ các giá trị từ enum sẽ làm cho điểm ints của bạn để giá trị khác, do đó, không sử dụng điều này trên enums mà bạn có thể muốn thay đổi tại một số điểm.

0

Có thể.

Nếu loại enum của bạn chỉ chứa giá trị số nguyên thì việc truyền trở nên rất đơn giản. Giả sử tôi có một kiểu enum như: - Create type monthenum as enum ('7', '8', '9', '10', '11', '12', '1', '2', '3', '4', '5', '6');

Bây giờ bạn có thể sử dụng đúc các giá trị enum để nguyên và hiển thị chúng như kỷ lục riêng biệt như sau: -

select (unnest(enum_range(null::monthenum))::text)::integer as monthvalue 

Hy vọng điều này sẽ giúp bạn, Ý tưởng là bạn có thể chuyển đổi enum thành văn bản và sau đó lại thành bất kỳ loại tương thích nào khác của giá trị enum của bạn. Bạn cũng có thể sử dụng cho vòng lặp để chuyển đổi từng giá trị.

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