?
本文檔使用 php中文網(wǎng)手冊(cè) 發(fā)布
Rules that are defined on INSERT, UPDATE, and DELETE are significantly different from the view rules described in the previous section. First, their CREATE RULE command allows more: 定義在INSERT,UPDATE,DELETE上的規(guī)則與前一章描述的視圖規(guī)則完全不同。 首先,他們的CREATE RULE命令允許更多:
它們可以沒(méi)有動(dòng)作。
它們可以有多個(gè)動(dòng)作。
他們可以是INSTEAD或ALSO(缺省)。
偽關(guān)系NEW和OLD變得有用了。
它們可以有規(guī)則資格條件。
第二,它們不是就地修改查詢樹,而是創(chuàng)建零個(gè)或多個(gè)新查詢樹并且可能把原始的那個(gè)仍掉。
保持其語(yǔ)法如下:
CREATE [ OR REPLACE ] RULE name AS ON event TO table [ WHERE condition ] DO [ ALSO | INSTEAD ] { NOTHING | command | ( command ; command ... ) }
牢牢記住,在隨后的內(nèi)容里,update rules(更新規(guī)則)意思是定義在INSERT,UPDATE,DELETE上的規(guī)則。
如果查詢樹的結(jié)果關(guān)系和命令類型與 CREATE RULE命令里給出的對(duì)象和事件一樣的話, 規(guī)則系統(tǒng)就把更新規(guī)則應(yīng)用上去。對(duì)于更新規(guī)則,規(guī)則系統(tǒng)創(chuàng)建一個(gè)查詢樹列表。一開(kāi)始查詢樹是空的 ,這里可以有零個(gè)(NOTHING 關(guān)鍵字)、一個(gè)、或多個(gè)動(dòng)作。為簡(jiǎn)單起見(jiàn),先看一個(gè)只有一個(gè)動(dòng)作的規(guī)則。 這個(gè)規(guī)則可以有零個(gè)或一個(gè)條件并且它可以是INSTEAD 或 ALSO(缺省)。
何為規(guī)則條件?它是一個(gè)限制條件,告訴規(guī)則動(dòng)作什么時(shí)候要做,什么時(shí)候不要做。 這個(gè)條件可以只引用NEW和/或OLD偽關(guān)系, 它們基本上是代表以對(duì)象形式給出的基本關(guān)系(但是有著特殊含義)。
所以,對(duì)這個(gè)單動(dòng)作的規(guī)則生成查詢樹,有下面三種情況。
來(lái)自規(guī)則動(dòng)作的查詢樹,附加了原始查詢樹的條件
來(lái)自規(guī)則動(dòng)作的帶有規(guī)則條件的查詢樹并且附加了原始查詢樹的條件
來(lái)自規(guī)則動(dòng)作帶有規(guī)則條件的查詢樹以及原始查詢樹的條件;以及附加了相反規(guī)則條件的原始查詢樹。
最后,如果規(guī)則是ALSO,那么最初未修改的查詢樹被加入到列表。 因?yàn)橹挥泻细竦?tt class="LITERAL">INSTEAD規(guī)則已經(jīng)在初始的查詢樹里面,所以對(duì)于單動(dòng)作規(guī)則最終得到一個(gè)或者兩個(gè)查詢樹。
對(duì)于ON INSERT規(guī)則,原來(lái)的查詢(如果沒(méi)有被INSERT取代)是在任何規(guī)則增加的動(dòng)作之前完成的。 這樣就允許動(dòng)作看到插入的行。但是對(duì)ON UPDATE和ON DELETE規(guī)則,原來(lái)的查詢是在規(guī)則增加的動(dòng)作之后完成的。 這樣就確保動(dòng)作可以看到將要更新或者將要?jiǎng)h除的行; 否則,動(dòng)作可能什么也不做,因?yàn)樗鼈儼l(fā)現(xiàn)沒(méi)有符合它們要求的行。
從規(guī)則動(dòng)作生成的查詢樹被再次送到重寫系統(tǒng),并且可能附加更多的規(guī)則,結(jié)果是更多的或更少的查詢樹。 所以規(guī)則動(dòng)作必須是另一個(gè)命令類型或者和規(guī)則所在的關(guān)系不同的另一個(gè)結(jié)果關(guān)系。 否則這樣的遞歸過(guò)程就會(huì)沒(méi)完沒(méi)了(規(guī)則的遞規(guī)展開(kāi)會(huì)被檢測(cè)到,并當(dāng)作一個(gè)錯(cuò)誤報(bào)告)。
在pg_rewrite系統(tǒng)表中 action 里的查詢樹只是模板。 因?yàn)樗麄兛梢砸梅秶淼?NEW 和 OLD,在使用它們之前必須做一些調(diào)整。對(duì)于任何對(duì) NEW 的引用, 都要先在初始查詢的目標(biāo)列中搜索對(duì)應(yīng)的條目。如果找到,把該條目表達(dá)式放到引用里。 否則NEW和OLD的含義一樣(UPDATE)或者被 NULL 替代(INSERT)。 任何對(duì) OLD 的引用都用結(jié)果關(guān)系的范圍表的引用替換。
在系統(tǒng)完成更新規(guī)則的附加之后,它再附加視圖規(guī)則到生成的查詢樹上。 視圖無(wú)法插入新的更新動(dòng)作,所以沒(méi)有必要向視圖重寫的輸出附加更新規(guī)則。
假設(shè)希望跟蹤 shoelace_data 關(guān)系中的 sl_avail 字段。 所以設(shè)置一個(gè)日志表和一條規(guī)則,這條規(guī)則每次在用UPDATE更新 shoelace_data表時(shí)都要往數(shù)據(jù)庫(kù)里寫一條記錄。
CREATE TABLE shoelace_log ( sl_name text, -- shoelace changed sl_avail integer, -- new available value log_who text, -- who did it log_when timestamp -- when ); CREATE RULE log_shoelace AS ON UPDATE TO shoelace_data WHERE NEW.sl_avail <> OLD.sl_avail DO INSERT INTO shoelace_log VALUES ( NEW.sl_name, NEW.sl_avail, current_user, current_timestamp );
現(xiàn)在有人鍵入:
UPDATE shoelace_data SET sl_avail = 6 WHERE sl_name = 'sl7';
然后看看日志表:
SELECT * FROM shoelace_log; sl_name | sl_avail | log_who | log_when ---------+----------+---------+---------------------------------- sl7 | 6 | Al | Tue Oct 20 16:14:45 1998 MET DST (1 row)
這是想要的,后端發(fā)生的事情如下。分析器創(chuàng)建查詢樹
UPDATE shoelace_data SET sl_avail = 6 FROM shoelace_data shoelace_data WHERE shoelace_data.sl_name = 'sl7';
這里是一個(gè)帶有條件表達(dá)式的 ON UPDATE 規(guī)則 log_shoelace 。
NEW.sl_avail <> OLD.sl_avail
和動(dòng)作
INSERT INTO shoelace_log VALUES ( new.sl_name, new.sl_avail, current_user, current_timestamp ) FROM shoelace_data new, shoelace_data old;
這個(gè)輸出看起來(lái)有點(diǎn)奇怪,因?yàn)槟悴荒軐?tt class="LITERAL">INSERT ... VALUES ... FROM。 這里的 FROM 子句只是表示查詢樹里有用于new 和old的范圍表記錄。 這些東西的存在是因?yàn)檫@樣一來(lái)它們就可以被INSERT命令的查詢樹里的變量引用。
該規(guī)則是一個(gè)有條件的ALSO規(guī)則,所以規(guī)則系統(tǒng)必須返回兩個(gè)查詢樹:更改過(guò)的規(guī)則動(dòng)作和原始查詢樹。 在第一步里,原始查詢的范圍表集成到規(guī)則動(dòng)作查詢樹里。生成:
INSERT INTO shoelace_log VALUES ( new.sl_name, new.sl_avail, current_user, current_timestamp ) FROM shoelace_data new, shoelace_data old, shoelace_data shoelace_data;
第二步把規(guī)則條件增加進(jìn)去,所以結(jié)果集限制為sl_avail改變了的行:
INSERT INTO shoelace_log VALUES ( new.sl_name, new.sl_avail, current_user, current_timestamp ) FROM shoelace_data new, shoelace_data old, shoelace_data shoelace_data WHERE new.sl_avail <> old.sl_avail;
這個(gè)東西看起來(lái)更奇怪,因?yàn)?tt class="LITERAL">INSERT ... VALUES也沒(méi)有WHERE子句,不過(guò)規(guī)劃器和執(zhí)行器對(duì)此并不在意。 它們畢竟還要為INSERT ... SELECT支持這種功能。
第三步把原始查詢樹的條件加進(jìn)去,把結(jié)果集進(jìn)一步限制成只有被初始查詢樹改變的行:
INSERT INTO shoelace_log VALUES ( new.sl_name, new.sl_avail, current_user, current_timestamp ) FROM shoelace_data new, shoelace_data old, shoelace_data shoelace_data WHERE new.sl_avail <> old.sl_avail AND shoelace_data.sl_name = 'sl7';
第四步把NEW引用替換為從原始查詢樹的目標(biāo)列來(lái)的或從結(jié)果關(guān)系來(lái)的相匹配的變量引用:
INSERT INTO shoelace_log VALUES ( shoelace_data.sl_name, 6, current_user, current_timestamp ) FROM shoelace_data new, shoelace_data old, shoelace_data shoelace_data WHERE 6 <> old.sl_avail AND shoelace_data.sl_name = 'sl7';
第五步,用結(jié)果關(guān)系引用把OLD引用替換掉:
INSERT INTO shoelace_log VALUES ( shoelace_data.sl_name, 6, current_user, current_timestamp ) FROM shoelace_data new, shoelace_data old, shoelace_data shoelace_data WHERE 6 <> shoelace_data.sl_avail AND shoelace_data.sl_name = 'sl7';
這就成了。因?yàn)橐?guī)則ALSO還輸出原始查詢樹。 簡(jiǎn)而言之,從規(guī)則系統(tǒng)輸出的是一個(gè)兩個(gè)查詢樹的列表,與下面語(yǔ)句相同:
INSERT INTO shoelace_log VALUES ( shoelace_data.sl_name, 6, current_user, current_timestamp ) FROM shoelace_data WHERE 6 <> shoelace_data.sl_avail AND shoelace_data.sl_name = 'sl7'; UPDATE shoelace_data SET sl_avail = 6 WHERE sl_name = 'sl7';
這就是執(zhí)行的順序以及規(guī)則要做的事情。
做的替換和追加的條件用于確保如果原始的查詢是下面這樣
UPDATE shoelace_data SET sl_color = 'green' WHERE sl_name = 'sl7';
就不會(huì)有日期記錄寫到表里。 因?yàn)檫@回原始查詢樹不包含有關(guān)sl_avail的目標(biāo)列表, NEW.sl_avail將被shoelace_data.sl_avail代替, 所以,規(guī)則生成的額外命令是:
INSERT INTO shoelace_log VALUES ( shoelace_data.sl_name, shoelace_data.sl_avail, current_user, current_timestamp ) FROM shoelace_data WHERE shoelace_data.sl_avail <> shoelace_data.sl_avail AND shoelace_data.sl_name = 'sl7';
并且條件將永遠(yuǎn)不可能是真值
如果最初的查詢修改多個(gè)行,它也能運(yùn)行。所以如果寫出下面命令:
UPDATE shoelace_data SET sl_avail = 0 WHERE sl_color = 'black';
實(shí)際上有四行被更新(sl1,sl2,sl3和sl4) 但sl3已經(jīng)是sl_avail = 0。 這回,原始的查詢樹條件已經(jīng)不一樣了,結(jié)果是規(guī)則生成下面的額外查詢樹
INSERT INTO shoelace_log SELECT shoelace_data.sl_name, 0, current_user, current_timestamp FROM shoelace_data WHERE 0 <> shoelace_data.sl_avail AND shoelace_data.sl_color = 'black';
這個(gè)查詢樹將肯定插入三個(gè)新的日志記錄。這也是完全正確的。
到這里就明白為什么原始查詢樹最后執(zhí)行非常重要。 如果UPDATE 將先被執(zhí)行,所有的行都已經(jīng)設(shè)為零, 所以記日志的INSERT將不能找到任何符合0 <> shoelace_data.sl_avail條件的行。
一個(gè)保護(hù)視圖關(guān)系,使其避免有人可以在其中INSERT, UPDATE, DELETE不可見(jiàn)數(shù)據(jù)的簡(jiǎn)單方法是讓那些查詢樹被丟棄。 創(chuàng)建下面規(guī)則
CREATE RULE shoe_ins_protect AS ON INSERT TO shoe DO INSTEAD NOTHING; CREATE RULE shoe_upd_protect AS ON UPDATE TO shoe DO INSTEAD NOTHING; CREATE RULE shoe_del_protect AS ON DELETE TO shoe DO INSTEAD NOTHING;
如果現(xiàn)在任何人試圖對(duì)視圖關(guān)系shoe做上面的任何操作,規(guī)則系統(tǒng)將應(yīng)用這些規(guī)則。 因?yàn)檫@些規(guī)則沒(méi)有動(dòng)作而且是INSTEAD,結(jié)果是生成的查詢樹將是空的并且整個(gè)查詢將變得空空如也, 因?yàn)榻?jīng)過(guò)規(guī)則系統(tǒng)處理后沒(méi)有什么東西剩下來(lái)用于優(yōu)化或執(zhí)行了。
一個(gè)更復(fù)雜的使用規(guī)則系統(tǒng)的方法是用規(guī)則系統(tǒng)創(chuàng)建一個(gè)重寫查詢樹的規(guī)則,使查詢樹對(duì)真實(shí)的表進(jìn)行正確的操作。 要在視圖shoelace上做這個(gè)工作,創(chuàng)建下面規(guī)則:
CREATE RULE shoelace_ins AS ON INSERT TO shoelace DO INSTEAD INSERT INTO shoelace_data VALUES ( NEW.sl_name, NEW.sl_avail, NEW.sl_color, NEW.sl_len, NEW.sl_unit ); CREATE RULE shoelace_upd AS ON UPDATE TO shoelace DO INSTEAD UPDATE shoelace_data SET sl_name = NEW.sl_name, sl_avail = NEW.sl_avail, sl_color = NEW.sl_color, sl_len = NEW.sl_len, sl_unit = NEW.sl_unit WHERE sl_name = OLD.sl_name; CREATE RULE shoelace_del AS ON DELETE TO shoelace DO INSTEAD DELETE FROM shoelace_data WHERE sl_name = OLD.sl_name;
如果你打算在視圖上支持RETURNING查詢,就要讓規(guī)則包含RETURNING計(jì)算視圖行數(shù)的子句。 這對(duì)于基于單個(gè)表的視圖來(lái)說(shuō)通常非?,嵥?,但是連接諸如shoelace之類的視圖很單調(diào)乏味。 一個(gè)插入情況的例子如下:
CREATE RULE shoelace_ins AS ON INSERT TO shoelace DO INSTEAD INSERT INTO shoelace_data VALUES ( NEW.sl_name, NEW.sl_avail, NEW.sl_color, NEW.sl_len, NEW.sl_unit ) RETURNING shoelace_data.*, (SELECT shoelace_data.sl_len * u.un_fact FROM unit u WHERE shoelace_data.sl_unit = u.un_name);
注意,這個(gè)規(guī)則同時(shí)支持該視圖上的INSERT和 INSERT RETURNING查詢,INSERT RETURNING將簡(jiǎn)單的忽略RETURNING子句。
假設(shè)現(xiàn)在有一包鞋帶到達(dá)商店,而且這是一大筆到貨。 但是不想每次都手工更新shoelace視圖。 取而代之的是創(chuàng)建了兩個(gè)小表:一個(gè)是可以從到貨清單中插入東西,另一個(gè)是一個(gè)特殊的技巧。 創(chuàng)建這些的命令如下:
CREATE TABLE shoelace_arrive ( arr_name text, arr_quant integer ); CREATE TABLE shoelace_ok ( ok_name text, ok_quant integer ); CREATE RULE shoelace_ok_ins AS ON INSERT TO shoelace_ok DO INSTEAD UPDATE shoelace SET sl_avail = sl_avail + NEW.ok_quant WHERE sl_name = NEW.ok_name;
現(xiàn)在你可以用來(lái)自部件列表的數(shù)據(jù)填充表shoelace_arrive了:
SELECT * FROM shoelace_arrive; arr_name | arr_quant ----------+----------- sl3 | 10 sl6 | 20 sl8 | 20 (3 rows)
讓我們迅速地看一眼當(dāng)前的數(shù)據(jù),
SELECT * FROM shoelace; sl_name | sl_avail | sl_color | sl_len | sl_unit | sl_len_cm ----------+----------+----------+--------+---------+----------- sl1 | 5 | black | 80 | cm | 80 sl2 | 6 | black | 100 | cm | 100 sl7 | 6 | brown | 60 | cm | 60 sl3 | 0 | black | 35 | inch | 88.9 sl4 | 8 | black | 40 | inch | 101.6 sl8 | 1 | brown | 40 | inch | 101.6 sl5 | 4 | brown | 1 | m | 100 sl6 | 0 | brown | 0.9 | m | 90 (8 rows)
把到貨鞋帶移到(shoelace_ok)中:
INSERT INTO shoelace_ok SELECT * FROM shoelace_arrive;
然后檢查結(jié)果
SELECT * FROM shoelace ORDER BY sl_name; sl_name | sl_avail | sl_color | sl_len | sl_unit | sl_len_cm ----------+----------+----------+--------+---------+----------- sl1 | 5 | black | 80 | cm | 80 sl2 | 6 | black | 100 | cm | 100 sl7 | 6 | brown | 60 | cm | 60 sl4 | 8 | black | 40 | inch | 101.6 sl3 | 10 | black | 35 | inch | 88.9 sl8 | 21 | brown | 40 | inch | 101.6 sl5 | 4 | brown | 1 | m | 100 sl6 | 20 | brown | 0.9 | m | 90 (8 rows) SELECT * FROM shoelace_log; sl_name | sl_avail | log_who| log_when ---------+----------+--------+---------------------------------- sl7 | 6 | Al | Tue Oct 20 19:14:45 1998 MET DST sl3 | 10 | Al | Tue Oct 20 19:25:16 1998 MET DST sl6 | 20 | Al | Tue Oct 20 19:25:16 1998 MET DST sl8 | 21 | Al | Tue Oct 20 19:25:16 1998 MET DST (4 rows)
從INSERT ... SELECT語(yǔ)句到這個(gè)結(jié)果經(jīng)過(guò)了長(zhǎng)長(zhǎng)的一段過(guò)程。 而且對(duì)它的描述將是本文檔的最后。 首先是生成分析器輸出:
INSERT INTO shoelace_ok SELECT shoelace_arrive.arr_name, shoelace_arrive.arr_quant FROM shoelace_arrive shoelace_arrive, shoelace_ok shoelace_ok;
現(xiàn)在應(yīng)用第一條規(guī)則shoelace_ok_ins把它轉(zhuǎn)換成
UPDATE shoelace SET sl_avail = shoelace.sl_avail + shoelace_arrive.arr_quant FROM shoelace_arrive shoelace_arrive, shoelace_ok shoelace_ok, shoelace_ok old, shoelace_ok new, shoelace shoelace WHERE shoelace.sl_name = shoelace_arrive.arr_name;
并且把原始的shoelace_ok的INSERT丟棄掉。 這樣重寫后的查詢?cè)俅蝹魅胍?guī)則系統(tǒng)并且第二次應(yīng)用了規(guī)則shoelace_upd生成
sting> UPDATE shoelace_data SET sl_name = shoelace.sl_name, sl_avail = shoelace.sl_avail + shoelace_arrive.arr_quant, sl_color = shoelace.sl_color, sl_len = shoelace.sl_len, sl_unit = shoelace.sl_unit FROM shoelace_arrive shoelace_arrive, shoelace_ok shoelace_ok, shoelace_ok old, shoelace_ok new, shoelace shoelace, shoelace old, shoelace new, shoelace_data shoelace_data WHERE shoelace.sl_name = shoelace_arrive.arr_name AND shoelace_data.sl_name = shoelace.sl_name;
同樣這是一個(gè)INSTEAD 規(guī)則并且前一個(gè)查詢樹被丟棄掉。 注意這個(gè)查詢?nèi)匀皇鞘褂靡晥Dshoelace, 但是規(guī)則系統(tǒng)還沒(méi)有完成這一步,所以它繼續(xù)在這上面應(yīng)用規(guī)則_RETURN, 然后得到:
UPDATE shoelace_data SET sl_name = s.sl_name, sl_avail = s.sl_avail + shoelace_arrive.arr_quant, sl_color = s.sl_color, sl_len = s.sl_len, sl_unit = s.sl_unit FROM shoelace_arrive shoelace_arrive, shoelace_ok shoelace_ok, shoelace_ok old, shoelace_ok new, shoelace shoelace, shoelace old, shoelace new, shoelace_data shoelace_data, shoelace old, shoelace new, shoelace_data s, unit u WHERE s.sl_name = shoelace_arrive.arr_name AND shoelace_data.sl_name = s.sl_name;
最后,應(yīng)用規(guī)則log_shoelace,生成額外的查詢樹
INSERT INTO shoelace_log SELECT s.sl_name, s.sl_avail + shoelace_arrive.arr_quant, current_user, current_timestamp FROM shoelace_arrive shoelace_arrive, shoelace_ok shoelace_ok, shoelace_ok old, shoelace_ok new, shoelace shoelace, shoelace old, shoelace new, shoelace_data shoelace_data, shoelace old, shoelace new, shoelace_data s, unit u, shoelace_data old, shoelace_data new shoelace_log shoelace_log WHERE s.sl_name = shoelace_arrive.arr_name AND shoelace_data.sl_name = s.sl_name AND (s.sl_avail + shoelace_arrive.arr_quant) <> s.sl_avail;
這樣,在規(guī)則系統(tǒng)用完所有的規(guī)則后返回生成的查詢樹。
所以最終得到兩個(gè)等效于下面 SQL 語(yǔ)句的查詢樹
INSERT INTO shoelace_log SELECT s.sl_name, s.sl_avail + shoelace_arrive.arr_quant, current_user, current_timestamp FROM shoelace_arrive shoelace_arrive, shoelace_data shoelace_data, shoelace_data s WHERE s.sl_name = shoelace_arrive.arr_name AND shoelace_data.sl_name = s.sl_name AND s.sl_avail + shoelace_arrive.arr_quant <> s.sl_avail; UPDATE shoelace_data SET sl_avail = shoelace_data.sl_avail + shoelace_arrive.arr_quant FROM shoelace_arrive shoelace_arrive, shoelace_data shoelace_data, shoelace_data s WHERE s.sl_name = shoelace_arrive.sl_name AND shoelace_data.sl_name = s.sl_name;
結(jié)果是從一個(gè)關(guān)系來(lái)的數(shù)據(jù)插入到另一個(gè)中,到了第三個(gè)中變成更新, 在到第四個(gè)中變成更新加上記日志,最后在第五個(gè)規(guī)則中縮減為兩個(gè)查詢。
有一個(gè)小細(xì)節(jié)有點(diǎn)讓人難受。 看看生成的兩個(gè)查詢,會(huì)發(fā)現(xiàn)shoelace_data關(guān)系在范圍表中出現(xiàn)了兩次而實(shí)際上絕對(duì)可以縮為一次。 因?yàn)橐?guī)劃器不處理這些,所以對(duì)規(guī)則系統(tǒng)輸出的INSERT的執(zhí)行規(guī)劃會(huì)是
Nested Loop -> Merge Join -> Seq Scan -> Sort -> Seq Scan on s -> Seq Scan -> Sort -> Seq Scan on shoelace_arrive -> Seq Scan on shoelace_data
在省略多余的范圍表后的結(jié)果將是
Merge Join -> Seq Scan -> Sort -> Seq Scan on s -> Seq Scan -> Sort -> Seq Scan on shoelace_arrive
這也會(huì)在日志關(guān)系中生成完全一樣的記錄。 因此,規(guī)則系統(tǒng)導(dǎo)致對(duì)表shoelace_data的一次多余的掃描,而且同樣多余的掃描會(huì)在UPDATE里也一樣多做一次。 不過(guò)要想把這些不足去掉是一樣太困難的活了。
最后對(duì)PostgreSQL規(guī)則系統(tǒng)及其功能做一個(gè)演示。 假設(shè)你向你的數(shù)據(jù)庫(kù)中添加一些比較罕見(jiàn)的鞋帶:
INSERT INTO shoelace VALUES ('sl9', 0, 'pink', 35.0, 'inch', 0.0); INSERT INTO shoelace VALUES ('sl10', 1000, 'magenta', 40.0, 'inch', 0.0);
建立一個(gè)視圖檢查哪種shoelace記錄在顏色上,對(duì)任何鞋子都不相配。 用于這個(gè)的視圖是
CREATE VIEW shoelace_mismatch AS SELECT * FROM shoelace WHERE NOT EXISTS (SELECT shoename FROM shoe WHERE slcolor = sl_color);
它的輸出是
SELECT * FROM shoelace_mismatch; sl_name | sl_avail | sl_color | sl_len | sl_unit | sl_len_cm ---------+----------+----------+--------+---------+----------- sl9 | 0 | pink | 35 | inch | 88.9 sl10 | 1000 | magenta | 40 | inch | 101.6
現(xiàn)在想這樣設(shè)置:沒(méi)有庫(kù)存的不匹配的鞋帶都從數(shù)據(jù)庫(kù)中刪除 為了讓這事對(duì)PostgreSQL有點(diǎn)難度,不直接刪除它們。 取而代之的是再創(chuàng)建一個(gè)視圖:
CREATE VIEW shoelace_can_delete AS SELECT * FROM shoelace_mismatch WHERE sl_avail = 0;
然后用下面方法做:
DELETE FROM shoelace WHERE EXISTS (SELECT * FROM shoelace_can_delete WHERE sl_name = shoelace.sl_name);
Voilà:
SELECT * FROM shoelace; sl_name | sl_avail | sl_color | sl_len | sl_unit | sl_len_cm ---------+----------+----------+--------+---------+----------- sl1 | 5 | black | 80 | cm | 80 sl2 | 6 | black | 100 | cm | 100 sl7 | 6 | brown | 60 | cm | 60 sl4 | 8 | black | 40 | inch | 101.6 sl3 | 10 | black | 35 | inch | 88.9 sl8 | 21 | brown | 40 | inch | 101.6 sl10 | 1000 | magenta | 40 | inch | 101.6 sl5 | 4 | brown | 1 | m | 100 sl6 | 20 | brown | 0.9 | m | 90 (9 rows)
對(duì)一個(gè)視圖的DELETE,這個(gè)視圖帶有一個(gè)總共使用了四個(gè)嵌套/連接的視圖的子查詢條件, 這四個(gè)視圖之一本身有一個(gè)擁有對(duì)一個(gè)視圖的子查詢條件,該條件計(jì)算使用的視圖的列; 最后重寫成了一個(gè)查詢樹,該查詢樹從一個(gè)真正的表里面把需要?jiǎng)h除的數(shù)據(jù)刪除。
我想在現(xiàn)實(shí)世界里只有很少的機(jī)會(huì)需要上面的這樣的構(gòu)造。但這些東西能運(yùn)轉(zhuǎn)肯定讓你舒服。