日本熟妇hd丰满老熟妇,中文字幕一区二区三区在线不卡 ,亚洲成片在线观看,免费女同在线一区二区

基本語句

本文介紹了基本語句的相關(guān)內(nèi)容。

賦值

為一個PL/SQL變量賦一個值可以被寫為:

    variable { := | = } expression;

正如以前所解釋的,這樣一個語句中的表達式被以一個 SQL SELECT命令被發(fā)送到主數(shù)據(jù)庫引擎的方式計算。 該表達式必須得到一個單一值(如果該變量是一個行或記錄變量, 它可能是一個行值)。該目標(biāo)變量可以是一個簡單變量( 可以選擇用一個塊名限定)、一個行或記錄變量的域或是一個簡單變量或域的數(shù)組元素。 等號(=)可以被用來代替 PL/SQL-兼容的 :=

如果該表達式的結(jié)果數(shù)據(jù)類型不匹配變量的數(shù)據(jù)類型,該值將被強制為變量的類型,就好像做了賦值造型一樣。 如果沒有用于所涉及到的數(shù)據(jù)類型的賦值造型可用, PL/SQL解釋器將嘗試以文本的方式轉(zhuǎn)換結(jié)果值,也就是在應(yīng)用結(jié)果類型的輸出函數(shù)之后再應(yīng)用變量類型的輸入函數(shù)。如果結(jié)果值的字符串形式無法被輸入函數(shù)所接受,這可能會導(dǎo)致由輸入函數(shù)產(chǎn)生的運行時錯誤。

例子:

    tax := subtotal * 0.06;
    my_record.user_id := 20;

執(zhí)行一個沒有結(jié)果的命令

對于任何不返回行的 SQL 命令(例如沒有一個RETURNING子句的INSERT),你可以通過把該命令直接寫在一個 PL/SQL 函數(shù)中執(zhí)行它。

任何出現(xiàn)在該命令文本中的PL/SQL變量名被當(dāng)作一個參數(shù),并且接著該變量的當(dāng)前值被提供為運行時該參數(shù)的值。這與早前描述的對表達式的處理完全相似。

當(dāng)以這種方式執(zhí)行一個 SQL 命令時,PL/SQL會為該命令緩存并重用執(zhí)行計劃。

有時候計算一個表達式或SELECT查詢但拋棄其結(jié)果是有用的,例如調(diào)用一個有副作用但是沒有有用的結(jié)果值的函數(shù)。在PL/SQL中要這樣做,可使用PERFORM語句:

    PERFORM query;

這會執(zhí)行query并且丟棄掉結(jié)果。以寫一個 SQL SELECT命令相同的方式寫該query,并且將初始的關(guān)鍵詞SELECT替換為PERFORM。對于WITH查詢,使用PERFORM并且接著把該查詢放在圓括號中(在這種情況中,該查詢只能返回一行)。PL/SQL變量將被替換到該查詢中,正像對不返回結(jié)果的命令所做的那樣,并且計劃被以相同的方式被緩存。還有,如果該查詢產(chǎn)生至少一行,特殊變量FOUND會被設(shè)置為真,而如果它不產(chǎn)生行則設(shè)置為假。

說明

我們可能期望直接寫SELECT能實現(xiàn)這個結(jié)果,但是當(dāng)前唯一被接受的方式是PERFORM。一個能返回行的 SQL 命令(例如SELECT)將被當(dāng)成一個錯誤拒絕,除非它像下一節(jié)中討論的有一個INTO子句。

一個例子:

    PERFORM create_mv('cs_session_page_requests_mv', my_query);

執(zhí)行一個有單一行結(jié)果的查詢

一個產(chǎn)生單一行(可能有多個列)的 SQL 命令的結(jié)果可以被賦值給一個記錄變量、行類型變量或標(biāo)量變量列表。這通過書寫基礎(chǔ) SQL 命令并增加一個INTO子句來達成。例如:

    SELECT select_expressions INTO [STRICT] target FROM ...;
    INSERT ... RETURNING expressions INTO [STRICT] target;
    UPDATE ... RETURNING expressions INTO [STRICT] target;
    DELETE ... RETURNING expressions INTO [STRICT] target;

其中target可以是一個記錄變量、一個行變量或一個有逗號分隔的簡單變量和記錄/行域列表。PL/SQL變量將被替換到該查詢的剩余部分中,并且計劃會被緩存,正如之前描述的對不返回行的命令所做的。這對SELECT、帶有RETURNINGINSERT/UPDATE/DELETE以及返回行集結(jié)果的工具命令(例如EXPLAIN)。除了INTO子句,SQL 命令和它在PL/SQL之外的寫法一樣。

說明

INTOSELECT的這種解釋和本數(shù)據(jù)庫常規(guī)的SELECT INTO命令有很大的不同,后者的INTO目標(biāo)是一個新創(chuàng)建的表。如果你想要在一個PL/SQL函數(shù)中從一個SELECT的結(jié)果創(chuàng)建一個表,請使用語法CREATE TABLE ... AS SELECT

如果一行或一個變量列表被用作目標(biāo),該查詢的結(jié)果列必須完全匹配該結(jié)果的結(jié)構(gòu),包括數(shù)量和數(shù)據(jù)類型,否則會發(fā)生一個運行時錯誤。當(dāng)一個記錄變量是目標(biāo)時,它會自動地把自身配置成查詢結(jié)果列組成的行類型。

INTO子句幾乎可以出現(xiàn)在 SQL 命令中的任何位置。通常它被寫成剛好在SELECT命令中的select_expressions列表之前或之后,或者在其他命令類型的命令最后。我們推薦你遵循這種慣例,以防PL/SQL的解析器在未來的版本中變得更嚴(yán)格。

如果STRICT沒有在INTO子句中被指定,那么target將被設(shè)置為該查詢返回的第一個行,或者在該查詢不返回行時設(shè)置為空(注意除非使用了ORDER BY,否則“第一行”的界定并不清楚)。第一行之后的任何結(jié)果行都會被拋棄。你可以檢查特殊的FOUND變量來確定是否返回了一行:

    SELECT * INTO myrec FROM emp WHERE empname = myname;
    IF NOT FOUND THEN
        RAISE EXCEPTION 'employee % not found', myname;
    END IF;

如果指定了STRICT選項,該查詢必須剛好返回一行或者將會報告一個運行時錯誤,該錯誤可能是NO_DATA_FOUND(沒有行)或TOO_MANY_ROWS(多于一行)。如果你希望捕捉該錯誤,可以使用一個異常塊,例如:

    BEGIN
    SELECT * INTO STRICT myrec FROM emp WHERE empname = myname;
        EXCEPTION
            WHEN NO_DATA_FOUND THEN
                RAISE EXCEPTION 'employee % not found', myname;
            WHEN TOO_MANY_ROWS THEN
                RAISE EXCEPTION 'employee % not unique', myname;
    END;

成功執(zhí)行一個帶STRICT的命令總是會將FOUND置為真。

對于帶有RETURNINGINSERT/UPDATE/DELETE,即使沒有指定STRICT,PL/SQL也會針對多于一個返回行的情況報告一個錯誤。這是因為沒有類似于ORDER BY的選項可以用來決定應(yīng)該返回哪個被影響的行。

如果為該函數(shù)啟用了 If print_strict_params,那么當(dāng)因為 STRICT的要求沒有被滿足而拋出一個錯誤時,該錯誤消息的DETAIL將包括傳遞給該查詢的參數(shù)信息。可以通過設(shè)置 plpgsql.print_strict_params為所有函數(shù)更改 print_strict_params設(shè)置,但是只有修改后被編譯的函數(shù)才會生效。也可以使用一個編譯器選項來為一個函數(shù)啟用它,例如:

    CREATE FUNCTION get_userid(username text) RETURN int
    IS
    #print_strict_params on
    DECLARE
    userid int;
    BEGIN
        SELECT users.userid INTO STRICT userid
            FROM users WHERE users.username = get_userid.username;
        RETURN userid;
    END;

失敗時,這個函數(shù)會產(chǎn)生一個這樣的錯誤消息

    ERROR:  query returned no rows
    DETAIL:  parameters: $1 = 'nosuchuser'
    CONTEXT:  PL/SQL function get_userid(text) line 6 at SQL statement
說明

STRICT選項匹配 Oracle PL/SQL 的SELECT INTO和相關(guān)語句的行為。

執(zhí)行動態(tài)命令

很多時候你將想要在PL/SQL函數(shù)中產(chǎn)生動態(tài)命令,也就是每次執(zhí)行中會涉及到不同表或不同數(shù)據(jù)類型的命令。PL/SQL通常對于命令所做的緩存計劃嘗試在這種情境下無法工作。要處理這一類問題,需要提供EXECUTE語句:

    EXECUTE command-string [ INTO [STRICT] target ] [ USING expression [, ... ] ];

其中command-string是一個能得到一個包含要被執(zhí)行命令字符串(類型text)的表達式。可選的target是一個記錄變量、一個行變量或者一個逗號分隔的簡單變量以及記錄/行域的列表,該命令的結(jié)果將存儲在其中。可選的USING表達式提供要被插入到該命令中的值。

在計算得到的命令字符串中,不會做PL/SQL變量的替換。任何所需的變量值必須在命令字符串被構(gòu)造時被插入其中,或者你可以使用下面描述的參數(shù)。

還有,對于通過EXECUTE執(zhí)行的命令不會有計劃被緩存。該命令反而在每次運行時都會被做計劃。因此,該命令字符串可以在執(zhí)行不同表和列上動作的函數(shù)中被動態(tài)創(chuàng)建。

INTO子句指定一個返回行的 SQL 命令的結(jié)果應(yīng)該被賦值到哪里。如果提供了一個行或變量列表,它必須完全匹配查詢結(jié)果的結(jié)構(gòu)(當(dāng)使用一個記錄變量時,它會自動把它自己配置為匹配結(jié)果結(jié)構(gòu))。如果返回多個行,只有第一個行會被賦值給INTO變量。如果沒有返回行,NULL 會被賦值給INTO變量。如果沒有指定INTO變量,該查詢結(jié)果會被拋棄。

如果給出了STRICT選項,除非該查詢剛好產(chǎn)生一行,否則將會報告一個錯誤

命令字符串可以使用參數(shù)值,它們在命令中用$1$2等引用。這些符號引用在USING子句中提供的值。這種方法常常更適合于把數(shù)據(jù)值作為文本插入到命令字符串中:它避免了將該值轉(zhuǎn)換為文本以及轉(zhuǎn)換回來的運行時負荷,并且它更不容易被 SQL 注入攻擊,因為不需要引用或轉(zhuǎn)義。一個例子是:

    EXECUTE 'SELECT count(*) FROM mytable WHERE inserted_by = $1 AND inserted <= $2'
       INTO c
       USING checked_user, checked_date;

需要注意的是,參數(shù)符號只能用于數(shù)據(jù)值 — 如果想要使用動態(tài)決定的表名或列名,你必須將它們以文本形式插入到命令字符串中。例如,如果前面的那個查詢需要在一個動態(tài)選擇的表上執(zhí)行,你可以這么做:

    EXECUTE 'SELECT count(*) FROM '
        || quote_ident(tabname)
        || ' WHERE inserted_by = $1 AND inserted <= $2'
       INTO c
       USING checked_user, checked_date;

一種更干凈的方法是為表名或者列名使用format()%I規(guī)范(被新行分隔的字符串會被串接起來):

    EXECUTE format('SELECT count(*) FROM %I '
       'WHERE inserted_by = $1 AND inserted <= $2', tabname)
       INTO c
       USING checked_user, checked_date;

另一個關(guān)于參數(shù)符號的限制是,它們只能在SELECTINSERTUPDATEDELETE命令中工作。在另一種語句類型(通常被稱為實用語句)中,即使值是數(shù)據(jù)值,你也必須將它們以文本形式插入。

在上面第一個例子中,帶有一個簡單的常量命令字符串和一些USING參數(shù)的EXECUTE命令在功能上等效于直接用PL/SQL寫的命令,并且允許自動發(fā)生PL/SQL變量替換。重要的不同之處在于,EXECUTE會在每一次執(zhí)行時根據(jù)當(dāng)前的參數(shù)值重新規(guī)劃該命令,而PL/SQL則是創(chuàng)建一個通用計劃并且將其緩存以便重用。在最佳計劃強依賴于參數(shù)值的情況中,使用EXECUTE來明確地保證不會選擇一個通用計劃是很有幫助的。

EXECUTE目前不支持SELECT INTO。但是可以執(zhí)行一個純的SELECT命令并且指定INTO作為EXECUTE本身的一部分。

說明

PL/SQL中的EXECUTE語句與EXECUTE 本數(shù)據(jù)庫服務(wù)器支持的 SQL 語句無關(guān)。服務(wù)器的EXECUTE語句不能直接在PL/SQL函數(shù)中使用(并且也沒有必要)。

在使用動態(tài)命令時經(jīng)常不得不處理單引號的轉(zhuǎn)義。我們推薦在函數(shù)體中使用美元符號引用來引用固定的文本。

動態(tài)值需要被小心地處理,因為它們可能包含引號字符。一個使用 format()的例子(這假設(shè)你用美元符號引用了函數(shù)體,因此引號不需要被雙寫):

    EXECUTE format('UPDATE tbl SET %I = $1 '
       'WHERE key = $2', colname) USING newvalue, keyvalue;

還可以直接調(diào)用引用函數(shù):

    EXECUTE 'UPDATE tbl SET '
            || quote_ident(colname)
            || ' = '
            || quote_literal(newvalue)
            || ' WHERE key = '
            || quote_literal(keyvalue);

這個例子展示了quote_identquote_literal函數(shù)的使用。為了安全,在進行一個動態(tài)查詢中的插入之前,包含列或表標(biāo)識符的表達式應(yīng)該通過quote_ident被傳遞。如果表達式包含在被構(gòu)造出的命令中應(yīng)該是字符串的值時,它應(yīng)該通過quote_literal被傳遞。這些函數(shù)采取適當(dāng)?shù)牟襟E來分別返回被封閉在雙引號或單引號中的文本,其中任何嵌入的特殊字符都會被正確地轉(zhuǎn)義。

因為quote_literal被標(biāo)記為STRICT,當(dāng)用一個空參數(shù)調(diào)用時,它總是會返回空。在上面的例子中,如果newvaluekeyvalue為空,整個動態(tài)查詢字符串會變成空,導(dǎo)致從EXECUTE得到一個錯誤。可以通過使用quote_nullable函數(shù)來避免這種問題,它工作起來和quote_literal相同,除了用空參數(shù)調(diào)用時會返回一個字符串NULL。例如:

    EXECUTE 'UPDATE tbl SET '
            || quote_ident(colname)
            || ' = '
            || quote_nullable(newvalue)
            || ' WHERE key = '
            || quote_nullable(keyvalue);

如果正在處理的參數(shù)值可能為空,那么通常應(yīng)該用quote_nullable來代替quote_literal

通常,必須小心地確保查詢中的空值不會遞送意料之外的結(jié)果。例如如果keyvalue為空,下面的WHERE子句

    'WHERE key = ' || quote_nullable(keyvalue)

永遠不會成功,因為在=操作符中使用空操作數(shù)得到的結(jié)果總是為空。如果想讓空和一個普通鍵值一樣工作,你應(yīng)該將上面的命令重寫成

    'WHERE key IS NOT DISTINCT FROM ' || quote_nullable(keyvalue)

請注意美元符號引用只對引用固定文本有用。嘗試寫出下面這個例子是一個非常糟糕的主意:

    EXECUTE 'UPDATE tbl SET '
            || quote_ident(colname)
            || ' = $$'
            || newvalue
            || '$$ WHERE key = '
            || quote_literal(keyvalue);

因為如果newvalue的內(nèi)容碰巧含有$$,那么這段代碼就會出問題。同樣的缺點可能適用于你選擇的任何其他美元符號引用定界符。因此,要想安全地引用事先不知道的文本,必須恰當(dāng)?shù)厥褂?code data-tag="code" class="code">quote_literal、quote_nullablequote_ident

動態(tài) SQL 語句也可以使用format函數(shù)來安全地構(gòu)造。例如:

    EXECUTE format('UPDATE tbl SET %I = %L '
       'WHERE key = %L', colname, newvalue, keyvalue);

%I等效于quote_ident并且 %L等效于quote_nullableformat函數(shù)可以和 USING子句一起使用:

    EXECUTE format('UPDATE tbl SET %I = $1 WHERE key = $2', colname)
       USING newvalue, keyvalue;

這種形式更好,因為變量被以它們天然的數(shù)據(jù)類型格式處理,而不是無條件地把它們轉(zhuǎn)換成文本并且通過%L引用它們。這樣效率更高。

獲得結(jié)果狀態(tài)

有好幾種方法可以判斷一條命令的效果。第一種方法是使用GET DIAGNOSTICS命令,其形式如下:

    GET [ CURRENT ] DIAGNOSTICS variable { = | := } item [ , ... ];

這條命令允許檢索系統(tǒng)狀態(tài)指示符。CURRENT是一個噪聲詞。每個item是一個關(guān)鍵字, 它標(biāo)識一個要被賦予給指定變量的狀態(tài)值(變量應(yīng)具有正確的數(shù)據(jù)類型來接收狀態(tài)值)。可用的診斷項表中展示了當(dāng)前可用的狀態(tài)項。冒號等號(:=)可以被用來取代 SQL 標(biāo)準(zhǔn)的=符號。例如:

    GET DIAGNOSTICS integer_var = ROW_COUNT;

可用的診斷項

名稱

類型

描述

ROW_COUNT

bigint

最近的SQL命令處理的行數(shù)

PG_CONTEXT

text

描述當(dāng)前調(diào)用棧的文本行

第二種判斷命令效果的方法是檢查一個名為FOUNDboolean類型的特殊變量。在每一次PL/SQL函數(shù)調(diào)用時,FOUND開始都為假。它的值會被下面的每一種類型的語句設(shè)置:

  • 如果一個SELECT INTO語句賦值了一行,它將把FOUND設(shè)置為真,如果沒有返回行則將之設(shè)置為假。

  • 如果一個PERFORM語句生成(并且拋棄)一行或多行,它將把FOUND設(shè)置為真,如果沒有產(chǎn)生行則將之設(shè)置為假。

  • 如果UPDATEINSERT以及DELETE語句影響了至少一行,它們會把FOUND設(shè)置為真,如果沒有影響行則將之設(shè)置為假。

  • 如果一個FETCH語句返回了一行,它將把FOUND設(shè)置為真,如果沒有返回行則將之設(shè)置為假。

  • 如果一個MOVE語句成功地重定位了游標(biāo),它將會把FOUND設(shè)置為真,否則設(shè)置為假。

  • 如果一個FORFOREACH語句迭代了一次或多次,它將會把FOUND設(shè)置為真,否則設(shè)置為假。當(dāng)循環(huán)退出時,FOUND用這種方式設(shè)置;在循環(huán)執(zhí)行中,盡管FOUND可能被循環(huán)體中的其他語句的執(zhí)行所改變,但它不會被循環(huán)語句修改。

  • 如果查詢返回至少一行,RETURN QUERYRETURN QUERY EXECUTE語句會把FOUND設(shè)為真, 如果沒有返回行則設(shè)置為假。

其他的PL/SQL語句不會改變FOUND的狀態(tài)。尤其需要注意的一點是:EXECUTE會修改GET DIAGNOSTICS的輸出,但不會修改FOUND的輸出。

FOUND是每個PL/SQL函數(shù)的局部變量;任何對它的修改只影響當(dāng)前的函數(shù)。

什么也不做

有時一個什么也不做的占位語句也很有用。例如,它能夠指示 if/then/else 鏈中故意留出的空分支。可以使用NULL語句達到這個目的:

    NULL;

例如,下面的兩段代碼是等價的:

    BEGIN
        y := x / 0;
    EXCEPTION
        WHEN division_by_zero THEN
            NULL;  -- 忽略錯誤
    END;
    BEGIN
        y := x / 0;
    EXCEPTION
        WHEN division_by_zero THEN  -- 忽略錯誤
    END;

究竟使用哪一種取決于各人的喜好。

說明

在Oracle的 PL/SQL 中,不允許出現(xiàn)空語句列表,并且因此在這種情況下必須使用NULL語句。而PL/SQL允許什么也不寫。