?
このドキュメントでは、 php中國(guó)語(yǔ)ネットマニュアル リリース
值表達(dá)式用在各種語(yǔ)法環(huán)境中,比如在SELECT命令的 目標(biāo)列表中,在INSERT或者UPDATE中用作新的列值, 或者在許多命令的搜索條件中使用。我們有時(shí)候把值表達(dá)式 的結(jié)果叫做scalar,以便與一個(gè)表表達(dá)式的結(jié)果相區(qū)別(是一個(gè)表)。因此值表達(dá) 式也叫做scalar expressions(或簡(jiǎn)稱 expressions)。表達(dá)式語(yǔ)法允許對(duì)來自基本部分的數(shù)值 進(jìn)行算術(shù)、邏輯、集合、和其它運(yùn)算。
值表達(dá)式是下列內(nèi)容之一:
一個(gè)常量或者子面值
一個(gè)子段引用
一個(gè)位置參數(shù)引用(在函數(shù)聲明體中或預(yù)編寫的語(yǔ)句中)
一個(gè)下標(biāo)表達(dá)式
一個(gè)子段選擇表達(dá)式
一個(gè)操作符調(diào)用
一個(gè)函數(shù)調(diào)用
一個(gè)聚集表達(dá)式
窗口函數(shù)調(diào)用
一個(gè)類型轉(zhuǎn)換
一個(gè)標(biāo)量子查詢
一個(gè)數(shù)組構(gòu)造器
一個(gè)行構(gòu)造器
一個(gè)在圓括弧里面的值表達(dá)式(可用于子表達(dá)式分組和覆蓋優(yōu)先級(jí))
除了這個(gè)列表以外,還有許多構(gòu)造可以歸類為表達(dá)式,但是不遵循任何通用 的語(yǔ)法規(guī)則。它們通常有函數(shù)或操作符的語(yǔ)義,并且在章Chapter 9里合適的位置描述。 一個(gè)例子是IS NULL子句。
我們已經(jīng)在節(jié)Section 4.1.2里有 討論過的內(nèi)容了。下面的節(jié)討論剩下的選項(xiàng)。
子段可以以下述格式被引用:
correlation.columnname
correlation是一個(gè)表的名子(可能有模式修飾), 或者是用FROM子句這樣的方法定義的表的別名, 而其它相關(guān)的名子可以用于任意SQL語(yǔ)句中)。如果在當(dāng)前查詢所使用的 所有表中,該子段名子是唯一的,那么這個(gè)相關(guān)名子和分隔用 的點(diǎn)就可以省略(參見Chapter 7)。
位置參數(shù)引用用于標(biāo)識(shí)從外部給SQL語(yǔ)句的參數(shù)。參數(shù)用于SQL函數(shù) 定義語(yǔ)句和預(yù)編寫的查詢。有些客戶端庫(kù)還支持在SQL命令字符串外邊 聲明數(shù)據(jù)值,這種情況下參數(shù)用于引用SQL字符串行外的數(shù)據(jù)。一個(gè)參 數(shù)的形式如下:
$number
比如下面這個(gè)dept
函數(shù)的定義
CREATE FUNCTION dept(text) RETURNS dept AS $$ SELECT * FROM dept WHERE name = $1 $$ LANGUAGE SQL;
在函數(shù)被調(diào)用的時(shí)候這里的$1將引用第一個(gè)參數(shù)。
如果一個(gè)表達(dá)式生成一個(gè)數(shù)組類型的數(shù)值,那么我們可以通過下面這樣的 表達(dá)式來提取數(shù)組中的元素
expression[subscript]
如果是多個(gè)相鄰的元素(an "array slice")可以用下面的方法抽取
expression[lower_subscript:upper_subscript]
每個(gè)subscript自己都是一個(gè)表達(dá)式, 它必須生成一個(gè)整數(shù)值。
通常,數(shù)組expression必須用圓括弧包圍, 但如果只是一個(gè)子段引用或者一個(gè)位置參數(shù),那么圓括弧可以省略。同樣, 如果源數(shù)組是多維的,那么多個(gè)下標(biāo)可以連接在一起。比如:
mytable.arraycolumn[4] mytable.two_d_column[17][34] $1[10:42] (arrayfunction(a,b))[42]
最后一個(gè)例子里的圓括弧是必須的。參閱Section 8.14 獲取有關(guān)數(shù)組的更多信息。
如果一個(gè)表達(dá)式生成一個(gè)復(fù)合類型(行類型),那么用下面的方法可以 抽取一個(gè)指定的子段
expression.fieldname
通常,行expression必須用圓括弧包圍, 但是如果要選取的表達(dá)式只是一個(gè)表引用或者位置參數(shù),可以省略圓括弧。 比如
mytable.mycolumn $1.somecolumn (rowfunction(a,b)).col3
因此,一個(gè)全稱的子段引用實(shí)際上只是一個(gè)子段選擇語(yǔ)法的特例。
一個(gè)重要的特殊情形是提取的表列是一個(gè)復(fù)合型的子段:
(compositecol).somefield (mytable.compositecol).somefield
在這里,括號(hào)是必須的,用來指出compositecol是列名而不是表名, mytable是表名而不是模式名。
操作符調(diào)用有三種語(yǔ)法:
expression operator expression (雙目中綴操作符) |
operator expression (單目前綴操作符) |
expression operator (單目后綴操作符) |
OPERATOR(schema.operatorname)
具體存在哪個(gè)操作符以及它們是單目還是雙目取決于系統(tǒng)或 用戶定義了什么操作符。章Chapter 9描述了內(nèi)置的操作符。
函數(shù)調(diào)用的語(yǔ)法是合法函數(shù)名(可能有模式名修飾)后面跟著包含參數(shù)列表的圓括?。?
function_name ([expression [, expression ... ]] )
比如,下面的代碼計(jì)算2的平方根:
sqrt(2)
內(nèi)置函數(shù)的列表在章Chapter 9里,其它函數(shù)可由用戶添加。
可選的可附加名子的參數(shù),參閱Section 4.3。
一個(gè)aggregate expression代表一個(gè)聚集 函數(shù)對(duì)查詢選出的行的處理。一個(gè)聚集函數(shù)把多個(gè)輸入縮減為 一個(gè)輸出值,比如給輸入求和或求平均。一個(gè)聚集表達(dá)式的語(yǔ)法是 下列之一:
aggregate_name (expression [ , ... ] [ order_by_clause ] ) aggregate_name (ALL expression [ , ... ] [ order_by_clause ] ) aggregate_name (DISTINCT expression [ , ... ] [ order_by_clause ] ) aggregate_name ( * )
這里的aggregate_name是 前面定義的聚集(可能是帶有模式的全稱), 而expression是一個(gè)本身不包含聚集表達(dá)式或窗口調(diào)用函數(shù)的任意值表達(dá)式。 order_by_clause是ORDER BY子句的一個(gè)選項(xiàng),下面會(huì)有描述。
第一種形式的聚集表達(dá)式為為每個(gè)輸入行調(diào)用聚集。
第二種形式與第一種等價(jià)(因?yàn)?tt class="LITERAL">ALL是缺省值)。
第三種形式為所有輸入行中所有唯一的非NULL值調(diào)用聚集。
最后一種形式調(diào)用一次聚集為每個(gè)輸入行調(diào)用一次聚集,
因?yàn)闆]有聲明特定的輸入值。通常它只用于count(*)
聚集函數(shù)
大多數(shù)的聚集函數(shù)在輸入時(shí)忽略了NULL,因此在一個(gè)或多個(gè)yield類型表達(dá)式中的行中的NULL被省略。 對(duì)所有的內(nèi)置聚集函數(shù)而言,這樣做是可以的,除非另行定義。
比如,count(*)生成輸入行的總數(shù);count(f1)生成f1不為NULL的輸入行數(shù): 因?yàn)?code class="FUNCTION">count忽略空值;count(distinct f1)生 成f1唯一且非NULL的行數(shù)。
一般情況下,輸入行會(huì)以非特定順序放入到聚集函數(shù)中,在許多情況下,這樣做是沒有影響的;如,無論以什么順序輸入,min
輸出相同的結(jié)果。
然而,一些聚集函數(shù)(如array_agg
和string_agg
)并非如此。
當(dāng)使用這種聚集函數(shù)時(shí),可以用order_by_clause選項(xiàng)指定輸入的順序。
除了它的表達(dá)式僅僅只是表達(dá)式,不能輸出列名或列數(shù)之外,order_by_clause與ORDER BY查詢子句有相同的語(yǔ)法結(jié)構(gòu),
在Section 7.5中有描述,如:
SELECT array_agg(a ORDER BY b DESC) FROM table;
在處理多參數(shù)聚集函數(shù)時(shí)需要注意,ORDER BY子句得再所有的聚集函數(shù)之后,如:
SELECT string_agg(a, ',' ORDER BY a) FROM table;
而不是:
SELECT string_agg(a ORDER BY a, ',') FROM table; -- incorrect
后者在語(yǔ)法上是有效的,但它表示的是,通過兩個(gè)ORDER BY關(guān)鍵子的單參數(shù)的聚集函數(shù)的調(diào)用(第二個(gè)是無用的,因?yàn)樗且粋€(gè)常量)。
如果order_by_clause中聲明了DISTINCT,那么所有的ORDER BY表達(dá)式必須 匹配常用的聚集參數(shù),也就是說,不能對(duì)沒有包含在DISTINCT列表中的表達(dá)式進(jìn)行排序。
Note: PostgreSQL擴(kuò)展可以在一個(gè)聚集函數(shù)中聲明DISTINCT和ORDER BY。
預(yù)定義的聚集函數(shù)在節(jié)Section 9.18里描述。 其它聚集函數(shù)可以由用戶增加。
一個(gè)聚集表達(dá)式只能在SELECT命令的結(jié)果列表或者HAVING子句里出現(xiàn)。禁止在其它子句里出現(xiàn)(比如WHERE 子句), 因?yàn)檫@些子句邏輯上在生成聚集結(jié)果之前計(jì)算。
如果一個(gè)聚集表達(dá)式出現(xiàn)在一個(gè)子查詢里(參閱節(jié)Section 4.2.10和Section 9.20), 聚集通常是在子查詢中進(jìn)行計(jì)算。但是如果聚集的參數(shù)只包含外層查詢的 變量則例外:這個(gè)聚集會(huì)屬于離他最近的外層查詢,并且在該查詢上進(jìn)行計(jì)算。 該聚集表達(dá)式整體上屬于它出現(xiàn)的子查詢對(duì)外層查詢的引用,其作用相當(dāng)于 子查詢每一次計(jì)算中的一個(gè)常量。前述限制(聚集表達(dá)式只能出現(xiàn)在結(jié)果列 或者HAVING子句中)只適用于聚集所屬的查詢層。
通過查詢篩選出的行的某些部分,窗口調(diào)用函數(shù)實(shí)現(xiàn)了類似于聚集函數(shù)的功能。 不同的是,窗口調(diào)用函數(shù)不需要將查詢結(jié)果打包成一行輸出,在查詢輸出中,每一行都是分開的。 然而,窗口調(diào)用函數(shù)可以掃描所有的行,根據(jù)窗口調(diào)用函數(shù)的分組規(guī)范(PARTITION BY列),這些行可能會(huì)是當(dāng)前行所在組的一部分。 一個(gè)窗口調(diào)用函數(shù)的語(yǔ)法如下:
function_name ([expression [, expression ... ]]) OVER ( window_definition ) function_name ([expression [, expression ... ]]) OVER window_name function_name ( * ) OVER ( window_definition ) function_name ( * ) OVER window_name
window_definition具有如下語(yǔ)法:
[ existing_window_name ] [ PARTITION BY expression [, ...] ] [ ORDER BY expression [ ASC | DESC | USING operator ] [ NULLS { FIRST | LAST } ] [, ...] ] [ frame_clause ]
同時(shí),選項(xiàng)frame_clause可以是:
[ RANGE | ROWS ] frame_start [ RANGE | ROWS ] BETWEEN frame_start AND frame_end
frame_start and frame_end可以是:
UNBOUNDED PRECEDING value PRECEDING CURRENT ROW value FOLLOWING UNBOUNDED FOLLOWING
在這里,expression表示的是任何自己不含窗口調(diào)用函數(shù)的值表達(dá)式。 PARTITION BY和ORDER BY列,本質(zhì)上,與所有查詢中的GROUP BY和ORDER BY具有相同的語(yǔ)法或語(yǔ)義, 除了它們的表達(dá)式只能作為表達(dá)式不能作為輸出列的名子或數(shù)。 window_name引用的是查詢語(yǔ)句中WINDOW子句定義的命名窗口規(guī)范。 命名窗口規(guī)范通常只是用OVERwindow_name來引用,但它也可以在括號(hào)里寫一個(gè)窗口名,并且 可以有選擇的使用排序和/或結(jié)構(gòu)子句(如果應(yīng)用這些子句的話,那么被引用的窗口必須不能有這些子句)。 后者語(yǔ)法遵循相同的規(guī)則(修改WINDOW子句中已有的窗口名)。 參閱SELECT查看更過資料。
對(duì)這些窗口函數(shù)(在這個(gè)框架而不是整個(gè)分區(qū)上的),frame_clause指定構(gòu)成window frame的行。 如果frame_end將它的缺省值省略為 CURRENT ROW,會(huì)有如下限制: frame_start不能為UNBOUNDED FOLLOWING,frame_end不能為UNBOUNDED PRECEDING,并且 相比frame_start,在上述列表中,frame_end選項(xiàng)不能出現(xiàn)的早。 例如:不允許RANGE BETWEEN CURRENT ROW AND valuePRECEDING。 默認(rèn)的幀選項(xiàng)是RANGE UNBOUNDED PRECEDING,該選項(xiàng)與RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW相同; 它將幀設(shè)置為允許所有分區(qū)中的行通過ORDER BY中最后出現(xiàn)的當(dāng)前行啟動(dòng)(如果沒有ORDER BY,那么就是所有行)。 一般情況下,UNBOUNDED PRECEDING意味著幀從分區(qū)中的第一行啟動(dòng),同樣類似的UNBOUNDED FOLLOWING表示幀以分區(qū)中的最后一行結(jié)束 (不管RANGE或ROWS模式)。 ROWS模式中,CURRENT ROW表示幀以當(dāng)前行啟動(dòng)或結(jié)束; 但是在RANGE模式中是以ORDER BY中第一次出現(xiàn)的行啟動(dòng),最后一次出現(xiàn)的行結(jié)束。 valuePRECEDING和valueFOLLOWING目前只允許ROWS模式。 這也就意味著,幀從當(dāng)前行之前或之后的許多行啟動(dòng)或結(jié)束。 value必須是整型表達(dá)式,而不能包含變量,聚集函數(shù),或者窗口函數(shù)。 值不能為空或負(fù),但可以是零,表示選擇當(dāng)前行本身。
內(nèi)置窗口函數(shù)在Table 9-44中有描述。 其他窗口函數(shù),用戶可以自己添加。同樣,任意內(nèi)置或用戶自定義聚集函數(shù)可以在窗口函數(shù)中使用。
使用*的語(yǔ)法可以用來調(diào)用參數(shù)的聚集函數(shù)為窗口函數(shù),如count(*) OVER (PARTITION BY x ORDER BY y)。 *通常不用于非聚集的窗口函數(shù)。與通常的聚集函數(shù)不同,聚集窗口函數(shù)不允許在 函數(shù)參數(shù)列中使用DISTINCT或ORDER BY。
窗口調(diào)用函數(shù)只能在SELECT列,或ORDER BY子句中使用。
More information about window functions can be found in Section 3.5, Section 9.19, Section 7.2.4.
一個(gè)類型轉(zhuǎn)換聲明一個(gè)從一種數(shù)據(jù)類型到另外一種數(shù)據(jù)類型的轉(zhuǎn)換。PostgreSQL接受兩種等效的類型轉(zhuǎn)換語(yǔ)法:
CAST ( expression AS type ) expression::type
CAST語(yǔ)法遵循SQL標(biāo)準(zhǔn):::語(yǔ)法是PostgreSQL歷史用法。
如果對(duì)一個(gè)已知類型的值表達(dá)式應(yīng)用轉(zhuǎn)換,它代表一個(gè)運(yùn)行時(shí)類型轉(zhuǎn)換。 只有在已經(jīng)定義了合適的類型轉(zhuǎn)換操作的情況下,該轉(zhuǎn)換才能成功。 請(qǐng)注意這一點(diǎn)和用于常量的轉(zhuǎn)換略有區(qū)別(如節(jié)Section 4.1.2.7所示)。一個(gè)應(yīng)用于字符串文本的 轉(zhuǎn)換表示給該字符串文本的值賦予一個(gè)初始類型,因此它對(duì)于任何類型 都會(huì)成功(如果字符串文本的內(nèi)容符合該數(shù)據(jù)類型的輸入語(yǔ)法)。
如果一個(gè)值表達(dá)式的值對(duì)某類型而言不存在混淆的情況,那么我們可以省略 明確的類型轉(zhuǎn)換(比如,在給一個(gè)表子段賦值的時(shí)候),而由系統(tǒng)自動(dòng)執(zhí)行類 型轉(zhuǎn)換。不過,自動(dòng)轉(zhuǎn)換只適用于那些系統(tǒng)表中標(biāo)記著"OK to apply implicitly"的轉(zhuǎn)換函數(shù)。 其它轉(zhuǎn)換函數(shù)必須用明確的轉(zhuǎn)換語(yǔ)法調(diào)用。這些限制是為了避免一些怪異的轉(zhuǎn)換被自動(dòng)的應(yīng)用。
我們也可以用函數(shù)風(fēng)格的語(yǔ)法聲明一個(gè)類型轉(zhuǎn)換:
typename ( expression )
不過,這個(gè)方法只能用于那些類型名同時(shí)也是有效函數(shù)名的類型。 比如,double precision就不能這么用,但是等效的float8 以。 同樣,interval,time和timestamp如果加了雙引號(hào)也只能這么用, 因?yàn)榇嬖谡Z(yǔ)法沖突。因此,函數(shù)風(fēng)格的類型轉(zhuǎn)換會(huì)導(dǎo)致不一致,所以應(yīng)該避免這么使用。
Note: 函數(shù)樣語(yǔ)法實(shí)際上就是一個(gè)函數(shù)調(diào)用。如果使用兩種標(biāo)準(zhǔn)轉(zhuǎn)換語(yǔ)法 做運(yùn)行時(shí)轉(zhuǎn)換,那么它將在內(nèi)部調(diào)用一個(gè)已注冊(cè)的函數(shù)執(zhí)行轉(zhuǎn)換。通常, 這種轉(zhuǎn)換函數(shù)和它們的輸出類型同名,但是可以移植的程序不能依賴這一點(diǎn)。 詳情請(qǐng)參閱CREATE CAST.
一個(gè)標(biāo)量子查詢是一個(gè)放在圓括弧里只返回一行一列的普通SELECT查詢(參閱章Chapter 7獲取有關(guān)書寫查詢的信息)。 該SELECT將被執(zhí)行,而其返回值將在周圍的值表達(dá)式中使用。把一個(gè)返回超過一行 或者超過一列的查詢用做標(biāo)量查詢是錯(cuò)誤的。不過,子查詢不返回行則 不算錯(cuò)誤(標(biāo)量結(jié)果被認(rèn)為是 NULL)。子查詢可以引用外圍查詢的變量, 這些變量在每次子查詢中當(dāng)做常量使用。參見節(jié)Section 9.20以獲取其它包含子查詢的表達(dá)式。
比如,下面的查詢找出每個(gè)州中的最大人口數(shù)量的城市:
SELECT name, (SELECT max(pop) FROM cities WHERE cities.state = states.name) FROM states;
一個(gè)數(shù)組構(gòu)造器是一個(gè)表達(dá)式,它從自身成員元素上構(gòu)造一個(gè)數(shù)組值。 一個(gè)簡(jiǎn)單的數(shù)組構(gòu)造器由關(guān)鍵子ARRAY,一個(gè)左方括弧[,一個(gè)或多個(gè)表示數(shù)組元素值的表達(dá)式(用逗號(hào)分隔),一個(gè)右方括弧]組成。 比如:
SELECT ARRAY[1,2,3+4]; array --------- {1,2,7} (1 row)
數(shù)組元素類型是常見的表達(dá)式成員類型,決定了對(duì)UNION或CASE結(jié)構(gòu)使用相同的規(guī)則(可查閱Section 10.5)。 你可以通過將數(shù)據(jù)結(jié)構(gòu)構(gòu)造成需要的類型來對(duì)此重寫,如:
SELECT ARRAY[1,2,22.7]::integer[]; array ---------- {1,2,23} (1 row)
For more on casting, see Section 4.2.9. 這樣做與將每個(gè)表達(dá)式逐個(gè)構(gòu)造成數(shù)據(jù)元素類型具有相同效果。 更多信息可參閱Section 4.2.9。
多維數(shù)組值可以通過嵌套數(shù)組構(gòu)造器的方法來制作。內(nèi)層構(gòu)造器中的ARRAY關(guān)鍵子可以省略。比如,下面的兩句生成同樣的結(jié)果:
SELECT ARRAY[ARRAY[1,2], ARRAY[3,4]]; array --------------- {{1,2},{3,4}} (1 row) SELECT ARRAY[[1,2],[3,4]]; array --------------- {{1,2},{3,4}} (1 row)
因?yàn)槎嗑S數(shù)組必須是方形,所以同層的內(nèi)層構(gòu)造器必須生成同維的子數(shù)組。 任何應(yīng)用到外ARRAY構(gòu)造上的構(gòu)造器自動(dòng)將其傳到所有的內(nèi)構(gòu)造上。
多維數(shù)組構(gòu)造器元素可以是任何生成合適數(shù)組的東西,而不僅僅是一個(gè)子ARRAY構(gòu)造。比如:
CREATE TABLE arr(f1 int[], f2 int[]); INSERT INTO arr VALUES (ARRAY[[1,2],[3,4]], ARRAY[[5,6],[7,8]]); SELECT ARRAY[f1, f2, '{{9,10},{11,12}}'::int[]] FROM arr; array ------------------------------------------------ {{{1,2},{3,4}},{{5,6},{7,8}},{{9,10},{11,12}}} (1 row)
因?yàn)閿?shù)組必須得有類型,因此在構(gòu)造一個(gè)空數(shù)組時(shí),必須明確的將其構(gòu)造成需要的類型,如:
SELECT ARRAY[]::integer[]; array ------- {} (1 row)
我們也可以從一個(gè)子查詢的結(jié)果中構(gòu)造一個(gè)數(shù)組。此時(shí),數(shù)組構(gòu)造器是關(guān)鍵子ARRAY跟著一個(gè)用圓括弧(不是方括弧)包圍的子查詢。比如:
SELECT ARRAY(SELECT oid FROM pg_proc WHERE proname LIKE 'bytea%'); ?column? ------------------------------------------------------------- {2011,1954,1948,1952,1951,1244,1950,2005,1949,1953,2006,31} (1 row)
子查詢必須只返回一個(gè)單獨(dú)的子段。生成的一維數(shù)組將為子查詢里每行結(jié)果 生成一個(gè)元素,元素類型匹配子查詢的輸出子段。
用ARRAY建立的數(shù)組下標(biāo)總是從壹開始。有關(guān)數(shù)組的 更多信息,參閱節(jié)Section 8.14。
行構(gòu)造器是一個(gè)從提供給它的成員子段數(shù)值中構(gòu)造行值(也叫復(fù)合類型值)的表達(dá)式。 一個(gè)行構(gòu)造器由關(guān)鍵子ROW、一個(gè)左圓括弧、零個(gè)或多個(gè) 作為行子段值的表達(dá)式(用逗號(hào)分隔)、一個(gè)右圓括弧組成。比如:
SELECT ROW(1,2.5,'this is a test');
如果在列表里有多個(gè)表達(dá)式,那么關(guān)鍵子ROW是可選的。
行構(gòu)造器可以包含rowvalue.*語(yǔ)法,它將被擴(kuò)展 為行值元素的列表,就像將.*語(yǔ)法用于一個(gè)SELECT列表頂層一樣。例如,如果表t有f1和f2兩個(gè)子段, 那么下面兩句是等價(jià)的:
SELECT ROW(t.*, 42) FROM t; SELECT ROW(t.f1, t.f2, 42) FROM t;
Note: 在PostgreSQL8.2之前,.*語(yǔ)法是不會(huì)被擴(kuò)展的,所以ROW(t.*, 42)將創(chuàng)建一個(gè)兩子段的行, 其第一個(gè)子段是另一行的值。新的行為通常更有用。如果你需要舊式的嵌套行 值的做法,請(qǐng)將內(nèi)部的行值寫成不含有.*,例如ROW(t, 42)。
缺省時(shí),ROW表達(dá)式創(chuàng)建的值是一個(gè)匿名的記錄類型。如果必要, 你可以把它轉(zhuǎn)換成一個(gè)命名的復(fù)合類型(既可以是一個(gè)表的行類型,也可以是 一個(gè)用CREATE TYPE AS創(chuàng)建的復(fù)合類型)。可能會(huì)需要一個(gè)明確 的轉(zhuǎn)換以避免歧義。比如:
CREATE TABLE mytable(f1 int, f2 float, f3 text); CREATE FUNCTION getf1(mytable) RETURNS int AS 'SELECT $1.f1' LANGUAGE SQL; -- No cast needed since only one getf1() exists SELECT getf1(ROW(1,2.5,'this is a test')); getf1 ------- 1 (1 row) CREATE TYPE myrowtype AS (f1 int, f2 text, f3 numeric); CREATE FUNCTION getf1(myrowtype) RETURNS int AS 'SELECT $1.f1' LANGUAGE SQL; -- Now we need a cast to indicate which function to call: SELECT getf1(ROW(1,2.5,'this is a test')); ERROR: function getf1(record) is not unique SELECT getf1(ROW(1,2.5,'this is a test')::mytable); getf1 ------- 1 (1 row) SELECT getf1(CAST(ROW(11,'this is a test',2.5) AS myrowtype)); getf1 ------- 11 (1 row)
行構(gòu)造器可以用于制作存儲(chǔ)在復(fù)合類型子段中的復(fù)合類型值,或者是傳遞給一個(gè) 接受復(fù)合類型參數(shù)的函數(shù)。另外,我們也可以用它比較兩個(gè)行值或者用IS NULL IS NOT NULL測(cè)試一個(gè)行值,比如:
SELECT ROW(1,2.5,'this is a test') = ROW(1, 3, 'not the same'); SELECT ROW(table.*) IS NULL FROM table; -- detect all-null rows
更多的細(xì)節(jié),請(qǐng)參閱節(jié)Section 9.21。行構(gòu)造器 還可以用于連接子查詢,這些在節(jié)Section 9.20里面有詳細(xì)討論。
子表達(dá)式的計(jì)算順序是沒有定義的。特別要指出的是,一個(gè)操作符或者函數(shù)的 輸入并不一定是按照從左向右的順序或者以某種特定的順序進(jìn)行計(jì)算的。
另外,如果一個(gè)表達(dá)式的結(jié)果可以通過只判斷它的一部分就可以得到, 那么其它子表達(dá)式就可以完全不計(jì)算了。比如,如果我們這么寫
SELECT true OR somefunc();
那么somefunc()就(可能)根本不會(huì)被調(diào)用。 即使像下面這樣寫也是一樣
SELECT somefunc() OR true;
請(qǐng)注意這和某些編程語(yǔ)言里從左向右"short-circuiting"是不一樣的。
因此,拿有副作用的函數(shù)作為復(fù)雜表達(dá)式的一部分是不明智的。 在WHERE和HAVING子句里依賴副作用或者是計(jì)算順序是 特別危險(xiǎn)的,因?yàn)檫@些子句都是作為生成一個(gè)執(zhí)行規(guī)劃的一部分進(jìn)行了大量的再處理。 在這些子句里的布爾表達(dá)式(AND/OR/NOT的組合) 可以用布爾代數(shù)運(yùn)算律允許的任何方式進(jìn)行識(shí)別。
如果需要強(qiáng)制計(jì)算順序,那么可以使用CASE構(gòu)造(參閱節(jié)Section 9.16)。比如,下面是 一種企圖避免在WHERE子句里被零除的不可靠方法:
SELECT ... WHERE x > 0 AND y/x > 1.5;
But this is safe:
SELECT ... WHERE CASE WHEN x > 0 THEN y/x > 1.5 ELSE false END;
使用該方式的CASE結(jié)構(gòu)會(huì)阻止優(yōu)化,因此只有在需要的時(shí)候才可以使用。 (特別是在這個(gè)例子中,通過使用y > 1.5*x可以很好的解決該問題)