茫茫網海中的冷日
         
茫茫網海中的冷日
發生過的事,不可能遺忘,只是想不起來而已!
 恭喜您是本站第 1669334 位訪客!  登入  | 註冊
主選單

Google 自訂搜尋

Goole 廣告

隨機相片
IMG_60D_00028.jpg

授權條款

使用者登入
使用者名稱:

密碼:


忘了密碼?

現在就註冊!

DB研討會 : [轉貼]Oracle 欄位自動流水號真是不人性化

發表者 討論內容
冷日
(冷日)
Webmaster
  • 註冊日: 2008/2/19
  • 來自:
  • 發表數: 15771
[轉貼]Oracle 欄位自動流水號真是不人性化

Oracle欄位自動流水號真是不人性化

幹嘛要用流水號
這個問題我之前也有思考過,最初設計用流水號是因為沒有適當欄位可以當key,因此設計一個欄位只單純區分每一個欄位,不過現在的資料庫設計時,因為正規化的設計下,其實一個table真的沒有辦法找出key或組合出key變成比較少見了,所以流水號其實只是偷懶的方式做區分而已。

MySQL的流水號

第一次使用流水號的欄位就是在MySQL資料庫的Schema設計上,由於MySQL設計基礎是簡單易用的資料庫,因此如果要一個欄位自動產生流水號真是非常的簡單,只需要再Create Table的時候補上一個關鍵字就可以搞定了。

這是官方的一個例子,只要欄位後面增加一個AUTO_INCREMENT的keyword,就表示該欄位會自動在新增一筆資料時,欄位數值+1,當然如果希望每次增加量不是1的情況也是可以補參數下去調整的。

CREATE TABLE animals ( id MEDIUMINT NOT NULL AUTO_INCREMENT, name CHAR(30) NOT NULL, PRIMARY KEY (id) );

Oracle的流水號

很不幸的,Oracle的流水號設計就沒有這麼輕鬆了,要把整個流水號的設計分成三個階段去描述:1. 建立Table、2. 建立Sequence、3. 建立Trigger。簡而言之就是利用Trigger於新增資料的時候偷偷將自動遞增的欄位數值補上,而補上的數值則由Sequence去控管,Table本身建立的時候不提供流水號建立。

以一個範例做簡單的介紹,第一個步驟是建立TableCREATE TABLE TEST_AUTO_INCREMENT_TABLE( ID NUMBER,DAT VARCHAR2(200) );

步驟二建立Sequence是利用Oracle內建的Sequence元件來做流水號的管理,當然Sequence不僅僅是拿來做流水號使用,但是我使用上幾乎只用來做這個功能就是了(乾笑)。CREATE SEQUENCE TABLE TEST_SEQ MINVALUE 1 MAXVALUE 999999999999999999999999999 INCREMENT BY 1 START WITH 1 CACHE 20 NOORDER NOCYCLE; 


步驟三是關鍵,將Sequence的流水號與Table之間做關聯,主要設計方式就是,在該Table發生Insert動作之前將SEQ的值填上流水號。CREATE TRIGGER TEST_AUTO_INCREMENT_TABLE_INSERT BEFORE INSERT ON TEST_AUTO_INCREMENT_TABLE FOR EACH ROW BEGIN SELECT TABLE TEST_SEQ.NEXTVAL INTO :NEW.ID FROM DUAL; END;

你會發現MySQL一行搞定的東西,跑到Oracle是分三段語法去整合,雖然說SEQUENCE本身不僅僅是提供流水號效果,而TRIGGER本身也是現在常用的控管方式,但是僅僅是為了流水號的功能就必須額外管理一個SEQUENCE/TRIGGER真是挺不人性化的。

原文出處:被遺忘的瞇瞇: Oracle欄位自動流水號真是不人性化
冷日
(冷日)
Webmaster
  • 註冊日: 2008/2/19
  • 來自:
  • 發表數: 15771
[轉貼]在 Oracle 中實作自動遞增欄位 (Oracle AUTO_INCREMENT)

在 Oracle 中實作自動遞增欄位 (Oracle AUTO_INCREMENT)

在 MySQL 的資料庫中,有一種方便的欄位型態 AUTO_INCREMENT,有自動遞增的功能,多半使用於 ID 欄位,作為 PRIMARY KEY。類似自動遞增的功能,在 MSSQL 有 Identity,甚至連 MS Access 都有個 AutoNumber 都可以很方便的去宣告使用。

人沒有完美的,資料庫同樣也是。功能強大的 Oracle 卻沒有內建這樣方便的功能欄位,從我開始接觸 Oracle 以來,一直覺得遺憾與不解的,幾年下來,看起來原廠是沒去 implement 這樣的功能欄位的打算,是令人有些扼脕。但是,我們還是有機會用拼拼湊湊的方式,搞一個那樣子的欄位出來。

Step1. 建立 Table:

CREATE TABLE tbl (
id NUMBER PRIMARY KEY,
val VARCHAR2(30)
);


Step2. 建立 Sequence:

CREATE SEQUENCE tbl_id_seq;

完成這兩步,我們就已經有了 INCREMENT (遞增)的功能了!

-- 新增紀錄
INSERT INTO tbl (id, val) VALUES (tbl_id_seq.nextval, 'row1_value');
INSERT INTO tbl (id, val) VALUES (tbl_id_seq.nextval, 'row2_value');
-- 撈出資料
SELECT * FROM tbl;
/**
輸出結果為:
ID VAL
---------- ------------------------------
1 row1_value
2 row2_value
*/

那,怎麼做到 AUTO (自動)呢?是的,就是用 Trigger!

Step3. 建立 Trigger:

CREATE OR REPLACE TRIGGER tbl_trg
BEFORE INSERT ON tbl
FOR EACH ROW
BEGIN
IF :new.id IS NULL THEN
SELECT tbl_id_seq.nextval INTO :new.id FROM dual;
END IF;
END;


這樣,AUTO_INCREMENT 都具備了,大功告成了!

-- 新增紀錄
INSERT INTO tbl (val) VALUES ('row3_value');
INSERT INTO tbl (id, val) VALUES (null, 'row4_value');
-- 撈出資料
SELECT * FROM tbl;
/**
輸出結果為:
ID VAL
---------- ------------------------------
1 row1_value
2 row2_value
3 row3_value
4 row4_value
*/

但是,如果就這樣結束,那本篇介紹的,不過是台兩光的三輪拼裝車。

這種欄位,有極大機率在實作情況下,需要即時取回剛剛新增那筆紀錄的 id 資料。在 MySQL 中有個 LAST_INSERT_ID() 來取得同一個連線 Session 中 AUTO_INCREMENT 所得到的 ID。那 Oracle 怎麼實作這功能?直接跟 Sequence 要它當時的值?如果在多人存取的環境下,這樣的做法能保證跟 Sequence 要到的那個數字,是你的還是後面又有人塞資料時候拿到的!?

INSERT ... RETURNING ... 是我們要的解答:

DECLARE
i NUMBER;
BEGIN
INSERT INTO tbl (val) VALUES ('row5_value') RETURNING id INTO i;
DBMS_OUTPUT.put_line('id : ' || i);
FOR rec IN (SELECT id, val FROM tbl)
LOOP
DBMS_OUTPUT.put_line('rec.id = ' || rec.id ||
'; rec.val = ' || rec.val);
END LOOP;
/**
輸出結果為:
id : 5
rec.id = 1; rec.val = row1_value
rec.id = 2; rec.val = row2_value
rec.id = 3; rec.val = row3_value
rec.id = 4; rec.val = row4_value
rec.id = 5; rec.val = row5_value
*/
INSERT INTO tbl (id, val) VALUES (NULL, 'row6_value') RETURNING id INTO i;
DBMS_OUTPUT.put_line('id : ' || i);
FOR rec IN (SELECT id, val FROM tbl)
LOOP
DBMS_OUTPUT.put_line('rec.id = ' || rec.id ||
'; rec.val = ' || rec.val);
END LOOP;
/**
輸出結果為:
id : 6
rec.id = 1; rec.val = row1_value
rec.id = 2; rec.val = row2_value
rec.id = 3; rec.val = row3_value
rec.id = 4; rec.val = row4_value
rec.id = 5; rec.val = row5_value
rec.id = 6; rec.val = row6_value
*/
END;


這做法雖然是輛拼裝車的,但是還不是太難使,倒也堪用。
不過,如果有機會能官方內建,總比建這建那拼拼湊湊的好!
難道,像人生一樣,就是要有那麼點遺憾,才是人生嗎?XD


原文出處: 在 Oracle 中實作自動遞增欄位 (Oracle AUTO_INCREMENT) :: 阿布洛格
冷日
(冷日)
Webmaster
  • 註冊日: 2008/2/19
  • 來自:
  • 發表數: 15771
[轉貼]Oracle 如何做到 SQL Server 的 Identity 欄位型態

Oracle 如何做到 SQL Server 的 Identity 欄位型態

在 DB table 規劃時,內部使用的 primary key 欄位常見用法分成兩派:使用 int 或是 GUID,在 SQL Server 上兩種做法都有對應的欄位型態,而在 Oracle 上就得要自行處理了,以 int 做法為例,在 SQL Server 中實作的欄位型態為 Identity,是一種自動累加固定值的識別碼,馬上來看看該如何在 Oracle 上實作 Identity 囉

實作做法說明

  1. 依實際需求建立 table 及欄位,並指定 primary key 欄位為 number 型態
  2. 建立 oracle sequence (序列) 用來取號
  3. 建立 trigger 在 insert data 時從 sequence 取號塞值

1. 建立 table

請依實際需求調整 table 欄位

  • 需要 primary key 為 number(10, 0)not null

    我這邊使用 Id 為欄位名稱

  • 指定 constraint

  • 語法範例


    create table UserProfile
    (
    Id number(10, 0) not null,
    Name VARCHAR2(50) not null,
    BirthDay date not null,
    Addr VARCHAR2(250) not null,
    constraint PK_UserProfile primary key (Id)
    )

2. 建立 Oracle Sequence

  • 用來自動循序增加數字
  • 語法範例


    create sequence SQ_UserProfile

3. 建立 Trigger

  • 在 insert 資料前到 sequence 取號寫入 primary key 欄位
  • 語法範例


    create or replace trigger TR_UserProfile
    before insert on UserProfile
    for each row
    begin
    select SQ_UserProfile.nextval into :new.Id from dual;
    end;

實際效果

  • 輸入時指定 100

    1input

  • 儲存 1

    2save

心得

一直以來都是使用 SQL Server 從來沒想過原來其他 db 沒有 identity 欄位型態,本來也沒想到可以這麼做,是使用 code first 產生 pl-sql 時發現原來 oracle 的 identity 可以透過上述方式建立,特別筆記一下

參考資訊


原文出處:Oracle 如何做到 SQL Server 的 Identity 欄位型態 - Yowko's Notes
冷日
(冷日)
Webmaster
  • 註冊日: 2008/2/19
  • 來自:
  • 發表數: 15771
[分享]冷日的 Oracle Identity 實做
這裡分享一下冷日的實做。
基於某前輩告訴冷日一般她們是用 Sequence 來讓 Oracle 幫你管 ID:
SELECT OXQ_TABLE_S.nextval, T.*
FROM OXQ_TABLE T

與此同時,我們需要一個 Sequence 給對應的 Table 用:
-- Create sequence
create sequence OXQ_TABLE_S
minvalue 1
maxvalue 2147483647
start with 1
increment by 1
cache 1000
;

最後,冷日和前輩討論後,再利用 Create Table 的 Default 來便利:
CREATE TABLE OXQ_TABLE (
  id          NUMBER DEFAULT OXQ_TABLE_S.NEXTVAL,
  description VARCHAR2(30)
);

這樣還蠻方便的!
前一個主題 | 下一個主題 | 頁首 | | |



Powered by XOOPS 2.0 © 2001-2008 The XOOPS Project|