2012-09-10 51 views

回答

18

雖然你可以不投枚舉整數噓聲解釋,你可以使用 PostgreSQL的特異性和可能未版本到版本兼容pg_enum系統目錄表中得到一個序號表示。

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) 

這看起來很簡單,但事實並非如此。注意:

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) 

從這裏就可以看出,enumsortorder提供訂貨,但沒有固定的「距離」。如果支持從枚舉中刪除值,它可能會在序列中創建'漏洞'。

爲了得到你需要使用row_number()窗函數來獲取排序的枚舉位置,pg_typeof獲得枚舉類型的oidregtype)。當需要使用相同標籤的多個枚舉時,您需要確保您返回正確的序號。

這個函數做的工作:

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; 

注:

  • STABLEIMMUTABLE,因爲從枚舉添加(或如果在PG支持以後添加,刪除)值將改變依靠排序來排序和中斷索引;所以
  • 你不能在一個索引表達式中使用它;和
  • 這是STRICT因爲它應該空輸入

現在你可以使用這個功能來CREATE CAST具體枚舉到integer返回null。您不能爲所有枚舉創建一個通用演員陣容到integer,因爲anyenum僞類型不能用於演員陣列。例如,如果我想允許演示happiness強制轉換爲整數,我會寫:

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

後,我可以成功執行:

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

注意,這可能是一個瘋狂要做的事情,沒有得到支持,而且很可能是一個可怕的想法。您的代碼必須注意,添加或(如果後來受支持)從枚舉中刪除值,序號值將更改爲

因爲PostgreSQL相信PostgreSQL認爲基於這種強制創建的索引(只有當函數被定義爲不可變時纔有可能)將會開始產生瘋狂和錯誤的結果(除了在它的末尾添加新值)當你說一個函數是不可變的。不要這樣做。

3

您不能將枚舉強制轉換爲整數。

可能能夠編寫一個custom operator來提取與某個值相關的數字,但我覺得很難相信這是值得的麻煩。

如果我需要這種信息,我會建立一個表併爲它設置一個外鍵引用,而不是使用枚舉。

11

您可以通過巧妙地濫用功能enum_range()來做到這一點。

如果您將枚舉值作爲enum_range()函數的第二個參數傳遞,並將NULL作爲第一個參數,那麼您將得到一個包含枚舉可以佔用的所有值的數組。然後你只需要用array_length對它們進行計數,並得到一個代表枚舉的整數。

下面是一個例子。這是我的枚舉:

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

這是我搞清楚INT爲「草案」值:

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

警告:去除枚舉值會讓你的整數點爲其他值,所以不要在你想要改變的枚舉上使用它。

0

是的,你可以。

如果您的枚舉類型只包含整數值,則鑄造變得非常簡單。 假設我有一個枚舉類型: - Create type monthenum as enum ('7', '8', '9', '10', '11', '12', '1', '2', '3', '4', '5', '6');

現在你可以用投枚舉值整數並顯示它們作爲獨立的記錄如下: -

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

希望這有助於你的想法您可以將枚舉轉換爲文本,然後再轉換爲您的枚舉值的任何其他兼容類型。您也可以使用for循環來逐個轉換值。