日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

在 DB2 通用數(shù)據(jù)庫中自動生成數(shù)值序列

 WindySky 2007-11-14
使用示例,我們的 SQL 專家向您展示了標(biāo)識列和最近引入的序列對象的典型用法,以自動生成數(shù)值。

簡介

IBM? DB2? Universal Database?(UDB) for Linux、UNIX? 和 Windows? V8.1 和最新發(fā)布的 DB2 Universal Database for z/OS? and OS/390? V8 都支持一組豐富的功能,這組功能可以自動生成數(shù)值序列。這些最新的 DB2 UDB 發(fā)行版在以前引入了標(biāo)識列的基礎(chǔ)上,又引入了數(shù)據(jù)庫 序列對象。在本文中,我們簡要討論標(biāo)識列和序列的典型用法,然后提供一些示例,對它們進(jìn)行演示并比較它們的功能。

    DB2 UDB for Linux、UNIX 和 Windows DB2 UDB for z/OS and OS/390 DB2 UDB for iSeries?
標(biāo)識列 V7 V6 V5R2
序列對象 V7.2 V8(在撰寫本文時(shí)還是 Beta 版) 計(jì)劃將來推出發(fā)行版
國際 SQL 標(biāo)準(zhǔn):已計(jì)劃將標(biāo)識列和序列對象列入國際 SQL 標(biāo)準(zhǔn)的下一版本。DB2 中實(shí)現(xiàn)的支持與所提議的內(nèi)容緊密匹配,而且該支持已列入國際 SQL 標(biāo)準(zhǔn)的當(dāng)前草案版本。




回頁首


生成數(shù)字序列的兩種方法

在 DB2 中可以用兩種方法自動生成一個(gè)數(shù)字序列:

IDENTITY 列

當(dāng)用 IDENTITY 屬性定義表的列時(shí),每當(dāng)將一行插入表時(shí),就會自動為該列生成一個(gè)數(shù)值。

SEQUENCE 對象

讓 DB2 自動生成數(shù)字序列的第二種方法是創(chuàng)建 SEQUENCE 對象??梢允褂?序列表達(dá)式(sequence expression)來引用序列對象。序列表達(dá)式可以出現(xiàn)在表達(dá)式能夠出現(xiàn)的大多數(shù)位置。序列表達(dá)式可以指定要返回的值是新生成的值還是以前生成的值。

如果序列引用是針對 下一值(next value),就會為序列自動生成一個(gè)數(shù)值,并將該數(shù)值作為序列表達(dá)式的結(jié)果返回。例如,如果我們假設(shè)已經(jīng)創(chuàng)建了名為 orders_seq 的序列,該序列表達(dá)式就返回為序列生成的下一個(gè)值:

	NEXT VALUE FOR orders_seq
                        

如果序列引用是針對 前一值(previous value),那么會將前一個(gè) SQL 語句中為序列生成的數(shù)值作為序列表達(dá)式的結(jié)果返回。該序列表達(dá)式返回由序列生成的前一個(gè)值:

	PREVIOUS VALUE FOR orders_seq
                        

注:當(dāng) DB2 UDB 引入序列時(shí),曾支持非 SQL 標(biāo)準(zhǔn)語法 NEXTVAL 代替 NEXT VALUE ,以及 PREVVAL 代替 PREVIOUS VALUE 。這些變體繼續(xù)受到支持。





回頁首


在標(biāo)識和序列之間做出選擇

雖然標(biāo)識和序列都用于生成數(shù)值,但您也許要根據(jù)特殊情況選擇使用一種來代替另一種。

在以下情況下,標(biāo)識列很有用:

  • 表中只有一列需要自動生成的值
  • 每一行都需要獨(dú)立的值
  • 用自動生成器來產(chǎn)生表的主鍵
  • 生成新值的進(jìn)程與對表的插入操作緊密聯(lián)系,無論插入操作是如何發(fā)生的

在以下情況下,序列對象很有用:

  • 要將從一個(gè)序列生成的值存儲到多個(gè)表中
  • 每個(gè)表有多個(gè)列需要自動生成的值(可能通過使用同一個(gè)序列或多個(gè)序列為每一行生成多個(gè)值)
  • 生成新值的進(jìn)程與任何對表的引用無關(guān)

與序列對象不同,標(biāo)識列是在表上定義的,因此需要某些限制。每個(gè)表最多只能有一個(gè)標(biāo)識列。當(dāng)創(chuàng)建一個(gè)列作為標(biāo)識列時(shí),對于該列必須使用確切的數(shù)字?jǐn)?shù)據(jù)類型。因?yàn)闃?biāo)識屬性為列生成一個(gè)值,這類似于 DEFAULT 子句所做的,所以在定義標(biāo)識列時(shí)不能指定 DEFAULT 子句。標(biāo)識列被隱式地定義成 NOT NULL 。





回頁首


示例 1. 組合客戶和供應(yīng)商表

要說明標(biāo)識列的典型用法,請考慮這樣一個(gè)表:它包含了虛構(gòu)的 Widget 公司的數(shù)據(jù)庫的客戶訂單信息。該公司希望為插入表中的每一行(訂單)自動生成訂單號。

用于我們的示例的 DDL

清單 1 所示,我們使用了用于訂單號的標(biāo)識列,他們將訂單號列定義成主鍵的一部分。注:該列中的以及它本身的 IDENTITY 屬性并沒有保證所生成的序列值是唯一的。但是, PRIMARY KEY 約束保證了表中行的唯一性。為了確保只將自動生成的值插入標(biāo)識列,他們指定了 GENERATED ALWAYS 子句。在每個(gè)季度結(jié)束時(shí),Widget 公司使用最后一個(gè)生成的 order_id 來確定這個(gè)季度接了多少訂單。選項(xiàng) NO CACHEORDER 確保了在系統(tǒng)故障的情況下,不廢棄未使用的標(biāo)識值。Widget 公司計(jì)劃通過使用 ALTER TABLE 語句,又從 1 重新開始訂單號列,以開始一個(gè)新的季度。

清單 1中顯式地顯示了標(biāo)識列的所有屬性,即使所設(shè)定的值是未指定值時(shí)的缺省值。因?yàn)槿笔≈禃蚋鞴?yīng)商實(shí)現(xiàn)而不同,所以指定所有選項(xiàng)是一個(gè)很好的編碼習(xí)慣。

清單 1. 使用 IDENTITY 列創(chuàng)建訂單表

        CREATE TABLE customer_orders_t (
                        order_id
                        INT NOT NULL
                        GENERATED ALWAYS
                        AS IDENTITY
                        (START WITH 1
                        INCREMENT BY 1
                        MINVALUE 1
                        NO MAXVALUE
                        NO CYCLE
                        NO CACHE
                        ORDER),
                        order_date
                        DATE NOT NULL,
                        cust_id
                        INT NOT NULL,
                        product_id
                        INT NOT NULL,
                        quantity
                        INT NOT NULL,
                        price
                        DECIMAL(10,2)
                        NOT NULL,
                        status
                        CHAR(9)
                        NOT NULL,
                        PRIMARY KEY (order_date, order_id))
                        

以下是將行插入表的 INSERT 語句的示例。

        INSERT INTO customer_orders_t
                        VALUES
                        (
                        DEFAULT, CURRENT DATE,
                        :cid, :pid, :qty, :cost, 'PENDING')
                        

Widget 公司不僅管理客戶訂單,而且還管理供應(yīng)商訂單。供應(yīng)商訂單在一個(gè)獨(dú)立的供應(yīng)商訂單表中,這個(gè)表的定義方式與定義客戶訂單表的方式非常相似。

        CREATE TABLE supplier_orders_t (
                        order_id
                        INT NOT NULL
                        GENERATED ALWAYS
                        AS IDENTITY
                        (
                        START WITH 1
                        INCREMENT BY 1
                        MINVALUE 1
                        NO MAXVALUE
                        NO CYCLE
                        NO CACHE
                        ORDER),
                        order_date
                        DATE NOT NULL,
                        supp_id
                        INT NOT NULL,
                        product_id
                        INT NOT NULL,
                        quantity
                        INT NOT NULL,
                        price
                        DECIMAL(10,2)
                        NOT NULL,
                        status
                        CHAR(9)
                        NOT NULL,
                        PRIMARY KEY (order_date, order_id))
                        

以下是將行插入 supplier_orders_t 表的 INSERT 語句的示例:

        INSERT INTO supplier_orders_t
                        VALUES
                        (
                        DEFAULT, CURRENT DATE,
                        :sid, :pid, :qty, :cost, 'PENDING')
                        

組合表

該公司意識到通過將客戶訂單表和供應(yīng)商訂單表組合成用于客戶和供應(yīng)商的一個(gè)總訂單表,可以獲得更大的效率和協(xié)同??蛻粲唵位蚬?yīng)商訂單之間唯一的區(qū)別是訂單是進(jìn)來還是出去,這反映在 STATUS 字段中。為了組合這些表,并造成最小中斷,他們計(jì)劃逐漸引入這種更改。他們的計(jì)劃中的步驟包括:

  1. 使訂單號同步,這些訂單號是為每個(gè)表生成的,這樣在表之間它們就是唯一的。
  2. 等待,直到完成所有非同步訂單。(或者,他們可以等到一個(gè)季度開始,那時(shí)將復(fù)位訂單號。)
  3. 逐步停止使用供應(yīng)商訂單表,使用客戶訂單表來管理來自客戶和供應(yīng)商的所有訂單。
  4. 清除。

第 1 步:使訂單號同步
要使在這兩個(gè)表中使用的生成的 order_id 號碼同步,則更改這兩個(gè)表,這樣可以由用于標(biāo)識列的 SEQUENCE 對象提供值,而不總是生成值。由單個(gè)序列 orders_seq 為這兩個(gè)表中的標(biāo)識列生成值。通過引用 NEXT VALUE 表達(dá)式中的 orders_seq ,修改每個(gè)表的 INSERT 語句以顯式地向標(biāo)識列提供值。 orders_seq 序列的定義方式如下:

        CREATE SEQUENCE orders_seq
                        AS INT
                        START WITH 1
                        INCREMENT BY 1
                        MINVALUE 1
                        NO MAXVALUE
                        NO CYCLE
                        NO CACHE
                        ORDER
                        

SET GENERATED BY DEFAULT子句將客戶訂單表和供應(yīng)商訂單表改成允許插入操作顯式地向標(biāo)識列提供值。

        ALTER TABLE customer_orders_t
                        ALTER COLUMN order_id
                        SET GENERATED BY DEFAULT
                        ALTER TABLE supplier_orders_t
                        ALTER COLUMN order_id
                        SET GENERATED BY DEFAULT
                        

在將兩個(gè)訂單表的全部 INSERT 語句修改為向 order_id 列提供顯式值且 orders_seq 序列從適當(dāng)?shù)闹甸_始的時(shí)候,發(fā)出 LOCK TABLE 語句來限制對這兩個(gè)表的插入操作。

以下是如何更改用于供應(yīng)商和客戶訂單表的 INSERT 語句:

        INSERT INTO customer_orders_t
                        VALUES
                        (
                        NEXT VALUE FOR orders_seq,
                        CURRENT DATE,
                        :cid, :pid, :qty, :cost, 'PENDING')
                        INSERT INTO supplier_orders_t
                        VALUES
                        (
                        NEXT VALUE FOR orders_seq,
                        CURRENT DATE,
                        :sid, :pid, :qty, :cost, 'PENDING')
                        

那么以下是如何修改 orders_seq 序列,使它從客戶訂單和供應(yīng)商訂單表的 order_id 標(biāo)識列所生成的最大值的后一個(gè)值開始。首先,使用 SELECT 語句確定該值:

        SELECT MAX(c.order_id),
                        MAX(s.order_id)
                        FROM customer_orders_t c, supplier_orders_t s
                        

例如,假設(shè)以上查詢返回兩個(gè)值:42331 和 57231。那么可以按以下方式改變 orders_seq 序列:

        ALTER SEQUENCE orders_seq
                        RESTART WITH 57232
                        

COMMIT 語句釋放表上的鎖,那么又可以對這兩個(gè)訂單表執(zhí)行插入操作了。所插入的值是從單個(gè)序列 orders_seq 生成的,并不是每個(gè) order_id 列擁有由標(biāo)識屬性各自獨(dú)立地生成的值,因此這些值在兩個(gè)表中將是唯一的。

請參閱 圖 1以獲取 第 1 步的圖釋。


圖 1. order_id 序列值覆蓋標(biāo)識列
第 1 步的圖形表示法

第 2 步:等待,直到同步了訂單為止
Widget 公司并不想等到季度開始(那時(shí)訂單被復(fù)位);而是決定監(jiān)控訂單的狀態(tài)。當(dāng)以下查詢的結(jié)果是空表時(shí),他們轉(zhuǎn)到 第 3 步

        SELECT order_id
                        FROM (
                        SELECT order_id
                        FROM customer_orders_t
                        WHERE status <> 'COMPLETED'
                        AND order_id < 57232)
                        AS x
                        UNION ALL (
                        SELECT order_id
                        FROM supplier_orders_t
                        WHERE status <> 'COMPLETED'
                        AND order_id < 57232)
                        

請參閱 圖 2以獲取 第 2 步的圖釋。


圖 2. 消除了所有潛在的重復(fù) order_id 號碼
第 2 步的圖形表示法

第 3 步:逐步停止使用供應(yīng)商訂單
要逐步停止使用 supplier_orders_t 表,通過按以下方式重命名該表,就可以使它暫時(shí)不可用:

        RENAME TABLE supplier_orders_t
                        TO supplier_orders_t_old
                        

然后,會創(chuàng)建一個(gè)視圖來允許對 supplier_orders_t 的現(xiàn)有引用繼續(xù)訪問底層數(shù)據(jù):

        CREATE VIEW supplier_orders_t
                        (order_id, order_date, supp_id, product_id, quantity,
                        price, status)
                        AS SELECT
                        order_id, order_date, cust_id, product_id, quantity,
                        price, status
                        FROM customer_orders_t
                        

現(xiàn)在傳統(tǒng)客戶和供應(yīng)商的所有活動訂單都在 customer_orders_t 表中進(jìn)行管理。要使將來更方便、更直觀地維護(hù)這些表,還需要在 第 4 步中執(zhí)行一些清除工作。

請參閱 圖 3以獲取 第 3 步的圖釋。


圖 3. 所有新訂單都進(jìn)入 customer_orders_t
第 3 步的圖形表示法

第 4 步:清除
因?yàn)楝F(xiàn)在必須只為一個(gè)列( order_id )生成訂單號,所以可以由標(biāo)識列生成值,而不是使用單獨(dú)的序列對象。同樣,表暫時(shí)不可用,而且標(biāo)識值被復(fù)位成由序列生成的下一個(gè)值。

        LOCK TABLE customer_orders_t
                        IN EXCLUSIVE MODE
                        VALUES NEXT VALUE FROM orders_seq
                        INTO :nextorder
                        

例如,假設(shè)上述查詢返回值:64243。那么,可以按以下方式改變 customer_orders_t 表:

        ALTER TABLE customer_orders_t
                        ALTER COLUMN order_id
                        SET GENERATED ALWAYS
                        RESTART WITH 64243
                        

每個(gè)實(shí)例(在這些實(shí)例中, INSERT 語句使用 orders_seq 序列)同樣需要更改,回到使用 DEFAULT ,如以前在 第 1 步中所顯示的?,F(xiàn)在可以刪除該序列:

        DROP SEQUENCE orders_seq
                        RESTRICT
                        

在歸檔了舊的供應(yīng)商訂單表中的數(shù)據(jù)之后,也可以刪除該表。

請參閱 圖 4以獲取 第 4 步的圖釋。


圖 4. 再次使用標(biāo)識列生成值,從 64243 開始
第 4 步的圖形表示法

調(diào)優(yōu)性能
既然使用 customer_orders_t 表的次數(shù)幾乎是原來的兩倍,Widget 公司決定將該表放在并行環(huán)境中。為了利用現(xiàn)在可以執(zhí)行的并行插入操作,他們決定通過高速緩存值來調(diào)優(yōu)該表的標(biāo)識列的性能。他們確定了高速緩存大小 50 適合于每小時(shí)創(chuàng)建的訂單數(shù)量以及出于任何原因而重新啟動數(shù)據(jù)庫系統(tǒng)的頻率。他們還更改了如何計(jì)算一個(gè)季度中實(shí)際創(chuàng)建的訂單數(shù),因此沒有理由強(qiáng)制按順序生成序列值。仍然繼續(xù)要滿足在一個(gè)季度中要生成唯一值的主要需求,因此做出了以下調(diào)整來增強(qiáng)用于標(biāo)識列的序列生成的性能:

        ALTER TABLE customer_orders_t
                        ALTER COLUMN order_id
                        SET CACHE 50
                        SET NO ORDER
                        





回頁首


示例 2. 收集衛(wèi)星讀數(shù)

示例 1中所示,序列允許跨多個(gè)表生成唯一值。序列還允許為一個(gè)表中的多個(gè)列自動生成它們的值。

對于該示例,請考慮一個(gè)圍繞行星或月亮的軌道衛(wèi)星。這個(gè)特定衛(wèi)星 SAT1 旨在獲取它的軌道上的 16 個(gè)不同點(diǎn)的數(shù)據(jù)讀數(shù)。收集該數(shù)據(jù)的表有三個(gè)列,在這些列中會自動生成值:一列使用標(biāo)識屬性生成讀數(shù)標(biāo)識,另兩列則從序列中獲取它們的值。請參閱 圖 5獲取說明。


圖 5. 衛(wèi)星和它的軌道上的 16 個(gè)數(shù)據(jù)讀取點(diǎn)
衛(wèi)星和它的軌道上的 16 個(gè)數(shù)據(jù)讀取點(diǎn)

用于我們的示例的 DDL
因?yàn)樽x數(shù)的數(shù)字可能非常大,標(biāo)識列使用 DECIMAL(31) 數(shù)據(jù)類型。

        CREATE TABLE SAT1_readings (
                        reading_id
                        DECIMAL(31)
                        NOT NULL PRIMARY KEY
                        GENERATED ALWAYS AS IDENTITY
                        (
                        START WITH 1
                        INCREMENT BY 1
                        MINVALUE 1
                        NO MAXVALUE
                        NO CYCLE
                        NO CACHE
                        ORDER),
                        orbit_location
                        SMALLINT NOT NULL,
                        horizon_adjustment
                        SMALLINT NOT NULL,
                        planet_image
                        BLOB(100
                        M))
                        

orbit_location 有一個(gè)值,該值從 0 到 15,代表軌道上獲取讀數(shù)的 16 個(gè)點(diǎn)。創(chuàng)建以下序列來生成這 16 個(gè)值的循環(huán)序列:

        CREATE SEQUENCE orbit_location_seq
                        AS SMALLINT
                        START WITH 0
                        INCREMENT BY 1
                        MINVALUE 0
                        MAXVALUE 15
                        CYCLE
                        NO CACHE
                        ORDER
                        

horizon_adjustment 值表示衛(wèi)星與水平面相關(guān)的位置在哪里。0 值表示它在水平面上,值 +4 表示它位于水平面上的最高點(diǎn),值 -4 表示它位于水平面下的最低點(diǎn)。這些序列從值 -4 開始,這既不是最小值,也不是最大值,因?yàn)樗鼘⒂糜诜匠淌街?,以便?jì)算水平調(diào)整值。序列對于每個(gè)軌道周期性循環(huán)。計(jì)算 horizon_adjustment 值時(shí)將使用以下序列:

        CREATE SEQUENCE horizon_adjustment_seq
                        AS SMALLINT
                        START WITH -4
                        INCREMENT BY 1
                        MINVALUE -7
                        MAXVALUE 8
                        CYCLE
                        NO CACHE
                        ORDER
                        

填充讀數(shù)表

每次產(chǎn)生讀數(shù)時(shí),以下 INSERT 語句就會填充表:

        INSERT INTO SAT1_readings
                        VALUES
                        (
                        DEFAULT, NEXT VALUE FOR orbit_location_seq,
                        ABS(NEXT VALUE FOR horizon_adjustment_seq) - 4,
                        :planet_image)
                        

在前 17 次讀取和相應(yīng)的 INSERT 語句之后,為列 reading_id (r_i)、orbit_location (o_l) 和 horizon_adjustment (h_a) 自動生成的值是:

r_i 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17.
o_l 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 0
h_a 0 -1 -2 -3 -4 -3 -2 -1 0 1 2 3 4 3 2 1 0

捕捉附加讀數(shù)
因?yàn)閮x器是足夠敏感的,在衛(wèi)星實(shí)際到達(dá)軌道之前,可以對行星進(jìn)行讀數(shù)。儀器的范圍允許在衛(wèi)星進(jìn)入其軌道之前,當(dāng)它接近行星時(shí),可以進(jìn)行 10 次讀數(shù)。要捕捉這些在正常軌道圈之外的附加讀數(shù),序列值從定義循環(huán)極限的 MINVALUEMAXVALUE 值的范圍外開始。

以下語句改變標(biāo)識值和序列值以允許讀取軌道上的 16 個(gè)點(diǎn)之前先獲取附加的 10 個(gè)讀數(shù)。RESTART 選項(xiàng)從指定值重新開始標(biāo)識列或序列,或者當(dāng)沒有指定值時(shí),在創(chuàng)建標(biāo)識列或序列時(shí)從用 START WITH 值指定的值重新開始。

        ALTER TABLE SAT1_readings
                        ALTER COLUMN reading_id
                        RESTART
                        ALTER SEQUENCE orbit_location_seq
                        RESTART WITH -10
                        ALTER SEQUENCE horizon_adjustment_seq
                        RESTART WITH -14
                        

以下的表顯示了:如果在相應(yīng)的 INSERT 語句之前執(zhí)行了以上三個(gè) ALTER 語句,那么前 17 個(gè)讀數(shù)將會是什么。這 17 個(gè)讀數(shù)包括在軌道之前獲得的 10 個(gè)讀數(shù)和在軌道上獲得的前七個(gè)讀數(shù):

r_i 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17.
o_l -10 -9 -8 -7 -6 -5 -4 -3 -2 -1 0 1 2 3 4 5 6
h_a 10 9 8 7 6 5 4 3 2 1 0 -1 -2 -3 -4 -3 -2




回頁首


結(jié)束語

DB2 支持兩種靈活的自動生成數(shù)值的方式:標(biāo)識列(與一個(gè)表緊密相連)和序列對象(獨(dú)立于任何表引用來生成值)。上面的示例說明了標(biāo)識列和序列對象用于自動生成數(shù)值的功能是多么強(qiáng)大以及有多么靈活。這些示例具體演示了標(biāo)識列和序列的以下功能:

  • 使用主鍵中的標(biāo)識列
  • 在兩個(gè)表的情況下使用序列對象
  • 為標(biāo)識列顯式地指定一個(gè)值,而不是生成值
  • 從預(yù)先確定的值開始值的序列
  • 從指定值重新開始標(biāo)識列值
  • 高速緩存標(biāo)識值以提高性能
  • 定義一個(gè)序列或標(biāo)識列,以允許值循環(huán)
  • 為序列指定一個(gè)開始值,該值大于為該序列定義的最小值
  • 為序列指定一個(gè)開始值,該值是負(fù)值
  • 定義一個(gè)序列,以生成先增加再減少的值
  • 確保按生成值的順序返回這些值

我們希望您發(fā)現(xiàn)序列和標(biāo)識會對您的應(yīng)用程序有用。

    本站是提供個(gè)人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多