39.5. ÐÑновнÑе опеÑаÑоÑÑ
- 39.5.1. ÐÑиÑваиваниÑ
- 39.5.2. ÐÑполнение командÑ, не возвÑаÑаÑÑей ÑезÑлÑÑаÑ
- 39.5.3. ÐÑполнение запÑоÑа, возвÑаÑаÑÑего Ð¾Ð´Ð½Ñ ÑÑÑокÑ
- 39.5.4. ÐÑполнение динамиÑеÑки ÑоÑмиÑÑемÑÑ ÐºÐ¾Ð¼Ð°Ð½Ð´
- 39.5.5. СÑаÑÑÑ Ð²ÑÐ¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ñ
- 39.5.6. Ðе делаÑÑ Ð½Ð¸Ñего
- 39.5.2. ÐÑполнение командÑ, не возвÑаÑаÑÑей ÑезÑлÑÑаÑ
Ð ÑÑом и поÑледÑÑÑÐ¸Ñ ÑÐ°Ð·Ð´ÐµÐ»Ð°Ñ Ð¾Ð¿Ð¸ÑÐ°Ð½Ñ Ð²Ñе ÑÐ¸Ð¿Ñ Ð¾Ð¿ÐµÑаÑоÑов, коÑоÑÑе Ð¿Ð¾Ð½Ð¸Ð¼Ð°ÐµÑ PL/pgSQL. ÐÑе, ÑÑо не пÑизнаеÑÑÑ Ð² каÑеÑÑве одного из ÑÑÐ¸Ñ Ñипов опеÑаÑоÑов, ÑÑиÑаеÑÑÑ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð¾Ð¹ SQL и оÑпÑавлÑеÑÑÑ Ð´Ð»Ñ Ð¸ÑÐ¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ Ð² оÑновнÑÑ Ð¼Ð°ÑÐ¸Ð½Ñ Ð±Ð°Ð·Ñ Ð´Ð°Ð½Ð½ÑÑ , как опиÑано в ÐодÑазделе 39.5.2 и ÐодÑазделе 39.5.3.
39.5.1. ÐÑиÑваиваниÑ
ÐÑиÑвоение знаÑÐµÐ½Ð¸Ñ Ð¿ÐµÑеменной PL/pgSQL запиÑÑваеÑÑÑ Ð² виде:
пеÑеменнаÑ{ := | = }вÑÑажение;
Ðак опиÑÑвалоÑÑ Ñанее, вÑÑажение в Ñаком опеÑаÑоÑе вÑÑиÑлÑеÑÑÑ Ñ Ð¿Ð¾Ð¼Ð¾ÑÑÑ SQL-ÐºÐ¾Ð¼Ð°Ð½Ð´Ñ SELECT, поÑÑлаемой в оÑновнÑÑ Ð¼Ð°ÑÐ¸Ð½Ñ Ð±Ð°Ð·Ñ Ð´Ð°Ð½Ð½ÑÑ
. ÐÑÑажение должно полÑÑиÑÑ Ð¾Ð´Ð½Ð¾ знаÑение (возможно, знаÑение ÑÑÑоки, еÑли пеÑÐµÐ¼ÐµÐ½Ð½Ð°Ñ ÑÑÑокового Ñипа или Ñипа record). Ð¦ÐµÐ»ÐµÐ²Ð°Ñ Ð¿ÐµÑÐµÐ¼ÐµÐ½Ð½Ð°Ñ Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð¿ÑоÑÑой пеÑеменной (возможно, дополненной именем блока), полем в пеÑеменной ÑÑÑокового Ñипа или запиÑи; или ÑлеменÑом маÑÑива, коÑоÑÑй ÑвлÑеÑÑÑ Ð¿ÑоÑÑой пеÑеменной или полем. ÐÐ»Ñ Ð¿ÑиÑÐ²Ð¾ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð¶Ð½Ð¾ иÑполÑзоваÑÑ Ð·Ð½Ð°Ðº ÑавенÑÑва (=) вмеÑÑо ÑовмеÑÑимого Ñ PL/SQL :=.
ÐÑли Ñип даннÑÑ ÑезÑлÑÑаÑа вÑÑÐ°Ð¶ÐµÐ½Ð¸Ñ Ð½Ðµ ÑооÑвеÑÑÑвÑÐµÑ ÑÐ¸Ð¿Ñ Ð´Ð°Ð½Ð½ÑÑ Ð¿ÐµÑеменной, ÑÑо знаÑение бÑÐ´ÐµÑ Ð¿ÑеобÑазовано к нÑÐ¶Ð½Ð¾Ð¼Ñ ÑÐ¸Ð¿Ñ Ñ Ð¸ÑполÑзованием пÑÐ¸Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¿ÑиÑÐ²Ð°Ð¸Ð²Ð°Ð½Ð¸Ñ (Ñм. Раздел 10.4). Ð ÑлÑÑае оÑÑÑÑÑÑÐ²Ð¸Ñ Ð¿ÑÐ¸Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¿ÑиÑÐ²Ð°Ð¸Ð²Ð°Ð½Ð¸Ñ Ð´Ð»Ñ ÑÑой паÑÑ Ñипов, инÑеÑпÑеÑаÑÐ¾Ñ PL/pgSQL попÑÑаеÑÑÑ Ð¿ÑеобÑазоваÑÑ Ð·Ð½Ð°Ñение ÑезÑлÑÑаÑа ÑеÑез ÑекÑÑовÑй ÑоÑмаÑ, Ñо еÑÑÑ Ð¿Ñименив ÑÑнкÑÐ¸Ñ Ð²Ñвода Ñипа ÑезÑлÑÑаÑа, а за ней ÑÑнкÑÐ¸Ñ Ð²Ð²Ð¾Ð´Ð° Ñипа пеÑеменной. ÐамеÑÑÑе, ÑÑо пÑи ÑÑом ÑÑнкÑÐ¸Ñ Ð²Ð²Ð¾Ð´Ð° Ð¼Ð¾Ð¶ÐµÑ Ð²ÑдаваÑÑ Ð¾Ñибки вÑемени вÑполнениÑ, еÑли не воÑпÑÐ¸Ð¼ÐµÑ ÑÑÑоковое пÑедÑÑавление знаÑÐµÐ½Ð¸Ñ ÑезÑлÑÑаÑа.
ÐÑимеÑÑ:
tax := subtotal * 0.06; my_record.user_id := 20;
39.5.2. ÐÑполнение командÑ, не возвÑаÑаÑÑей ÑезÑлÑÑаÑ
Ð ÑÑнкÑии на PL/pgSQL можно вÑполниÑÑ Ð»ÑбÑÑ ÐºÐ¾Ð¼Ð°Ð½Ð´Ñ SQL, не возвÑаÑаÑÑÑÑ ÑÑÑок, пÑоÑÑо напиÑав ÑÑÑ ÐºÐ¾Ð¼Ð°Ð½Ð´Ñ (напÑимеÑ, INSERT без пÑÐµÐ´Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ RETURNING).
ÐÐ¼Ñ Ð»Ñбой пеÑеменной PL/pgSQL в ÑекÑÑе ÐºÐ¾Ð¼Ð°Ð½Ð´Ñ ÑаÑÑмаÑÑиваеÑÑÑ ÐºÐ°Ðº паÑамеÑÑ, а заÑем ÑекÑÑее знаÑение пеÑеменной подÑÑавлÑеÑÑÑ Ð² каÑеÑÑве знаÑÐµÐ½Ð¸Ñ Ð¿Ð°ÑамеÑÑа во вÑÐµÐ¼Ñ Ð²ÑполнениÑ. ÐÑо в ÑоÑноÑÑи ÑÐ¾Ð²Ð¿Ð°Ð´Ð°ÐµÑ Ñ Ð¾Ð¿Ð¸Ñанной Ñанее обÑабоÑкой Ð´Ð»Ñ Ð²ÑÑажений; за подÑобноÑÑÑми обÑаÑиÑеÑÑ Ðº ÐодÑазделÑ 39.10.1.
ÐÑи вÑполнении SQL-ÐºÐ¾Ð¼Ð°Ð½Ð´Ñ Ñаким обÑазом, PL/pgSQL Ð¼Ð¾Ð¶ÐµÑ ÐºÐµÑиÑоваÑÑ Ð¸ повÑоÑно иÑполÑзоваÑÑ Ð¿Ð»Ð°Ð½ вÑÐ¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ñ, как обÑÑждаеÑÑÑ Ð² ÐодÑазделе 39.10.2.
Ðногда бÑÐ²Ð°ÐµÑ Ð¿Ð¾Ð»ÐµÐ·Ð½Ð¾ вÑÑиÑлиÑÑ Ð·Ð½Ð°Ñение вÑÑÐ°Ð¶ÐµÐ½Ð¸Ñ Ð¸Ð»Ð¸ запÑоÑа SELECT, но оÑказаÑÑÑÑ Ð¾Ñ ÑезÑлÑÑаÑа, напÑимеÑ, пÑи вÑзове ÑÑнкÑии, Ñ ÐºÐ¾ÑоÑой еÑÑÑ Ð¿Ð¾Ð±Ð¾ÑнÑе ÑÑÑекÑÑ, но Ð½ÐµÑ Ð¿Ð¾Ð»ÐµÐ·Ð½Ð¾Ð³Ð¾ ÑезÑлÑÑаÑа. ÐÐ»Ñ ÑÑого в PL/pgSQL, иÑполÑзÑеÑÑÑ Ð¾Ð¿ÐµÑаÑÐ¾Ñ PERFORM:
PERFORM запÑоÑ;
ÐÑа команда вÑполнÑÐµÑ Ð·Ð°Ð¿ÑÐ¾Ñ Ð¸ оÑбÑаÑÑÐ²Ð°ÐµÑ ÑезÑлÑÑаÑ. ÐапÑоÑÑ Ð¿Ð¸ÑÑÑÑÑ Ñаким же обÑазом, как и в команде SQL SELECT, но клÑÑевое Ñлово SELECT заменÑеÑÑÑ Ð½Ð° PERFORM. ÐÐ»Ñ Ð·Ð°Ð¿ÑоÑов WITH поÑле PERFORM нÑжно помеÑÑиÑÑ Ð·Ð°Ð¿ÑÐ¾Ñ Ð² Ñкобки. (Ð ÑÑом ÑлÑÑае запÑÐ¾Ñ Ð¼Ð¾Ð¶ÐµÑ Ð²ÐµÑнÑÑÑ ÑолÑко Ð¾Ð´Ð½Ñ ÑÑÑокÑ.) ÐеÑеменнÑе PL/pgSQL бÑдÑÑ Ð¿Ð¾Ð´ÑÑÐ°Ð²Ð»ÐµÐ½Ñ Ð² запÑÐ¾Ñ Ñак же, как и в командÑ, не возвÑаÑаÑÑÑÑ ÑезÑлÑÑаÑ, план запÑоÑа Ñакже кеÑиÑÑеÑÑÑ. ÐÑоме Ñого, ÑпеÑиалÑÐ½Ð°Ñ Ð¿ÐµÑÐµÐ¼ÐµÐ½Ð½Ð°Ñ FOUND ÑÑÑанавливаеÑÑÑ Ð² иÑÑинÑ, еÑли запÑÐ¾Ñ Ð²Ð¾Ð·Ð²ÑаÑаеÑ, по кÑайней меÑе, Ð¾Ð´Ð½Ñ ÑÑÑокÑ, или ложÑ, еÑли не возвÑаÑÐ°ÐµÑ Ð½Ð¸ одной ÑÑÑоки (Ñм. ÐодÑаздел 39.5.5).
ÐÑимеÑание
Ðожно пÑедположиÑÑ, ÑÑо Ñакой же ÑезÑлÑÑÐ°Ñ Ð¿Ð¾Ð»ÑÑаеÑÑÑ Ð½ÐµÐ¿Ð¾ÑÑедÑÑвенно командой SELECT, но в наÑÑоÑÑее вÑÐµÐ¼Ñ Ð¸ÑполÑзование PERFORM ÑвлÑеÑÑÑ ÐµÐ´Ð¸Ð½ÑÑвеннÑм ÑпоÑобом. Ðоманда SQL, коÑоÑÐ°Ñ Ð¼Ð¾Ð¶ÐµÑ Ð²Ð¾Ð·Ð²ÑаÑаÑÑ ÑÑÑоки, напÑÐ¸Ð¼ÐµÑ SELECT, бÑÐ´ÐµÑ Ð¾Ñклонена Ñ Ð¾Ñибкой, еÑли не Ð¸Ð¼ÐµÐµÑ Ð¿ÑÐµÐ´Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ INTO, как опиÑано в ÑледÑÑÑем Ñазделе.
ÐÑимеÑ:
PERFORM create_mv('cs_session_page_requests_mv', my_query);39.5.3. ÐÑполнение запÑоÑа, возвÑаÑаÑÑего Ð¾Ð´Ð½Ñ ÑÑÑокÑ
РезÑлÑÑÐ°Ñ SQL-командÑ, возвÑаÑаÑÑей Ð¾Ð´Ð½Ñ ÑÑÑÐ¾ÐºÑ (возможно из неÑколÑкиÑ
ÑÑолбÑов), Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð¿ÑиÑвоен пеÑеменной Ñипа record, пеÑеменной ÑÑÑокового Ñипа или ÑпиÑÐºÑ ÑкалÑÑнÑÑ
пеÑеменнÑÑ
. ÐÐ»Ñ ÑÑого нÑжно к оÑновной команде SQL добавиÑÑ Ð¿Ñедложение INTO. Так, напÑимеÑ:
SELECTвÑÑажениÑ_selectINTO [STRICT]ÑелÑFROM ...; INSERT ... RETURNINGвÑÑажениÑINTO [STRICT]ÑелÑ; UPDATE ... RETURNINGвÑÑажениÑINTO [STRICT]ÑелÑ; DELETE ... RETURNINGвÑÑажениÑINTO [STRICT]ÑелÑ;
где ÑÐµÐ»Ñ Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð¿ÐµÑеменной Ñипа record, ÑÑÑоковой пеÑеменной или ÑазделÑннÑм запÑÑÑми ÑпиÑком ÑкалÑÑнÑÑ
пеÑеменнÑÑ
, полей запиÑи/ÑÑÑоки. ÐеÑеменнÑе PL/pgSQL подÑÑавлÑÑÑÑÑ Ð² оÑÑавÑÑÑÑÑ ÑаÑÑÑ Ð·Ð°Ð¿ÑоÑа, план вÑÐ¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ ÐºÐµÑиÑÑеÑÑÑ, Ñак же, как бÑло опиÑано вÑÑе Ð´Ð»Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´, не возвÑаÑаÑÑиÑ
ÑÑÑоки. ÐÑо ÑабоÑÐ°ÐµÑ Ð´Ð»Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´ SELECT, INSERT/UPDATE/DELETE Ñ Ð¿Ñедложением RETURNING и ÑлÑжебнÑÑ
команд, возвÑаÑаÑÑиÑ
ÑезÑлÑÑÐ°Ñ Ð² виде набоÑа ÑÑÑок (ÑакиÑ
как EXPLAIN). Ðа иÑклÑÑением пÑÐµÐ´Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ INTO, ÑÑо Ñе же SQL-командÑ, как иÑ
можно напиÑаÑÑ Ð²Ð½Ðµ PL/pgSQL.
ÐодÑказка
ÐбÑаÑиÑе внимание, ÑÑо Ð´Ð°Ð½Ð½Ð°Ñ Ð¸Ð½ÑеÑпÑеÑаÑÐ¸Ñ SELECT Ñ INTO полноÑÑÑÑ Ð¾ÑлиÑаеÑÑÑ Ð¾Ñ Postgres Pro ÐºÐ¾Ð¼Ð°Ð½Ð´Ñ SELECT INTO, где в INTO ÑказÑваеÑÑÑ Ð²Ð½Ð¾Ð²Ñ ÑÐ¾Ð·Ð´Ð°Ð²Ð°ÐµÐ¼Ð°Ñ ÑаблиÑа. ÐÑли Ð²Ñ Ñ
оÑиÑе в ÑÑнкÑии на PL/pgSQL ÑоздаÑÑ ÑаблиÑÑ, оÑнованнÑÑ Ð½Ð° ÑезÑлÑÑаÑе ÐºÐ¾Ð¼Ð°Ð½Ð´Ñ SELECT, иÑполÑзÑйÑе ÑинÑакÑÐ¸Ñ CREATE TABLE ... AS SELECT.
ÐÑли ÑезÑлÑÑÐ°Ñ Ð·Ð°Ð¿ÑоÑа пÑиÑваиваеÑÑÑ Ð¿ÐµÑеменной ÑÑÑокового Ñипа или ÑпиÑÐºÑ Ð¿ÐµÑеменнÑÑ
, Ñо они Ð´Ð¾Ð»Ð¶Ð½Ñ Ð² ÑоÑноÑÑи ÑооÑвеÑÑÑвоваÑÑ Ð¿Ð¾ колиÑеÑÑÐ²Ñ Ð¸ Ñипам даннÑÑ
ÑÑолбÑам ÑезÑлÑÑаÑа, инаÑе пÑоизойдÑÑ Ð¾Ñибка во вÑÐµÐ¼Ñ Ð²ÑполнениÑ. ÐÑли иÑполÑзÑеÑÑÑ Ð¿ÐµÑÐµÐ¼ÐµÐ½Ð½Ð°Ñ Ñипа record, Ñо она авÑомаÑиÑеÑки пÑиводиÑÑÑ Ðº ÑÑÑÐ¾ÐºÐ¾Ð²Ð¾Ð¼Ñ ÑÐ¸Ð¿Ñ ÑезÑлÑÑаÑа запÑоÑа.
ÐÑедложение INTO Ð¼Ð¾Ð¶ÐµÑ Ð¿Ð¾ÑвиÑÑÑÑ Ð¿ÑакÑиÑеÑки в лÑбом меÑÑе SQL-командÑ. ÐбÑÑно его запиÑÑваÑÑ Ð½ÐµÐ¿Ð¾ÑÑедÑÑвенно пеÑед или ÑÑÐ°Ð·Ñ Ð¿Ð¾Ñле ÑпиÑка вÑÑажениÑ_select в SELECT или в конÑе ÐºÐ¾Ð¼Ð°Ð½Ð´Ñ Ð´Ð»Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´ дÑÑгиÑ
Ñипов. РекомендÑеÑÑÑ ÑледоваÑÑ ÑÑÐ¾Ð¼Ñ ÑоглаÑÐµÐ½Ð¸Ñ Ð½Ð° ÑлÑÑай, еÑли пÑавила ÑазбоÑа PL/pgSQL ÑжеÑÑоÑаÑÑÑ Ð² бÑдÑÑиÑ
веÑÑиÑÑ
.
ÐÑли Ñказание STRICT оÑÑÑÑÑÑвÑÐµÑ Ð² пÑедложении INTO, Ñо Ñели пÑиÑваиваеÑÑÑ Ð¿ÐµÑÐ²Ð°Ñ ÑÑÑока, возвÑаÑÑÐ½Ð½Ð°Ñ Ð·Ð°Ð¿ÑоÑом; или NULL, еÑли запÑÐ¾Ñ Ð½Ðµ веÑнÑл ÑÑÑок. (ÐамеÑим, ÑÑо понÑÑие «пеÑÐ²Ð°Ñ ÑÑÑока» опÑеделÑеÑÑÑ Ð½ÐµÐ¾Ð´Ð½Ð¾Ð·Ð½Ð°Ñно без ORDER BY.) ÐÑе оÑÑалÑнÑе ÑÑÑоки ÑезÑлÑÑаÑа поÑле пеÑвой оÑбÑаÑÑваÑÑÑÑ. Ðожно пÑовеÑиÑÑ ÑпеÑиалÑнÑÑ Ð¿ÐµÑеменнÑÑ FOUND (Ñм. ÐодÑаздел 39.5.5), ÑÑÐ¾Ð±Ñ Ð¾Ð¿ÑеделиÑÑ, бÑла ли возвÑаÑена запиÑÑ:
SELECT * INTO myrec FROM emp WHERE empname = myname;
IF NOT FOUND THEN
RAISE EXCEPTION 'СоÑÑÑдник % не найден', 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 'СоÑÑÑдник % не найден', myname;
WHEN TOO_MANY_ROWS THEN
RAISE EXCEPTION 'СоÑÑÑдник % Ñже ÑÑÑеÑÑвÑеÑ', myname;
END; ÐоÑле ÑÑпеÑного вÑÐ¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ñ Ñ Ñказанием STRICT, знаÑение пеÑеменной FOUND вÑегда ÑÑÑанавливаеÑÑÑ Ð² иÑÑинÑ.
ÐÐ»Ñ INSERT/UPDATE/DELETE Ñ RETURNING, PL/pgSQL возвÑаÑÐ°ÐµÑ Ð¾ÑибкÑ, еÑли вÑбÑано более одной ÑÑÑоки, даже в Ñом ÑлÑÑае, когда Ñказание STRICT оÑÑÑÑÑÑвÑеÑ. Так пÑоиÑÑ
Ð¾Ð´Ð¸Ñ Ð¿Ð¾ÑомÑ, ÑÑо Ñ ÑÑиÑ
команд Ð½ÐµÑ Ð²Ð¾Ð·Ð¼Ð¾Ð¶Ð½Ð¾ÑÑи, Ñипа ORDER BY, ÑказаÑÑ ÐºÐ°ÐºÐ°Ñ Ð¸Ð· задейÑÑвованнÑÑ
ÑÑÑок должна бÑÑÑ Ð²Ð¾Ð·Ð²ÑаÑена.
ÐÑли Ð´Ð»Ñ ÑÑнкÑии вклÑÑÑн Ñежим print_strict_params, Ñо пÑи возникновении оÑибки, ÑвÑзанной Ñ Ð½Ð°ÑÑÑением ÑÑÐ»Ð¾Ð²Ð¸Ñ STRICT, в деÑалÑнÑÑ (DETAIL) ÑаÑÑÑ ÑообÑÐµÐ½Ð¸Ñ Ð¾Ð± оÑибке бÑÐ´ÐµÑ Ð²ÐºÐ»ÑÑена инÑоÑмаÑÐ¸Ñ Ð¾ паÑамеÑÑаÑ
, пеÑеданнÑÑ
запÑоÑÑ. ÐзмениÑÑ Ð·Ð½Ð°Ñение print_strict_params можно ÑÑÑановкой паÑамеÑÑа plpgsql.print_strict_params. Ðо ÑÑо повлиÑÐµÑ ÑолÑко на ÑÑнкÑии, ÑкомпилиÑованнÑе поÑле изменениÑ. ÐÐ»Ñ ÐºÐ¾Ð½ÐºÑеÑной ÑÑнкÑии можно иÑполÑзоваÑÑ Ñказание компилÑÑоÑа, напÑимеÑ:
CREATE FUNCTION get_userid(username text) RETURNS int
AS $$
#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;
$$ LANGUAGE plpgsql;Ð ÑлÑÑае ÑÐ±Ð¾Ñ Ð±ÑÐ´ÐµÑ ÑÑоÑмиÑовано пÑимеÑно Ñакое ÑообÑение об оÑибке
ERROR: query returned no rows DETAIL: parameters: $1 = 'nosuchuser' CONTEXT: PL/pgSQL function get_userid(text) line 6 at SQL statement
ÐÑимеÑание
С Ñказанием STRICT поведение SELECT INTO и ÑвÑзаннÑÑ
опеÑаÑоÑов ÑооÑвеÑÑÑвÑÐµÑ Ð¿ÑинÑÑÐ¾Ð¼Ñ Ð² Oracle PL/SQL.
Ðак дейÑÑвоваÑÑ Ð² ÑлÑÑаÑÑ , когда ÑÑебÑеÑÑÑ Ð¾Ð±ÑабоÑаÑÑ Ð½ÐµÑколÑко ÑÑÑок ÑезÑлÑÑаÑа, опиÑано в ÐодÑазделе 39.6.4.
39.5.4. ÐÑполнение динамиÑеÑки ÑоÑмиÑÑемÑÑ ÐºÐ¾Ð¼Ð°Ð½Ð´
ЧаÑÑо ÑÑебÑеÑÑÑ Ð´Ð¸Ð½Ð°Ð¼Ð¸ÑеÑки ÑоÑмиÑоваÑÑ ÐºÐ¾Ð¼Ð°Ð½Ð´Ñ Ð²Ð½ÑÑÑи ÑÑнкÑий на PL/pgSQL, Ñо еÑÑÑ Ñакие командÑ, в коÑоÑÑÑ
пÑи каждом вÑполнении могÑÑ Ð¸ÑполÑзоваÑÑÑÑ ÑазнÑе ÑаблиÑÑ Ð¸Ð»Ð¸ ÑÐ¸Ð¿Ñ Ð´Ð°Ð½Ð½ÑÑ
. ÐбÑÑно PL/pgSQL кеÑиÑÑÐµÑ Ð¿Ð»Ð°Ð½Ñ Ð²ÑÐ¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ (как опиÑано в ÐодÑазделе 39.10.2), но в ÑлÑÑае Ñ Ð´Ð¸Ð½Ð°Ð¼Ð¸ÑеÑкими командами ÑÑо не бÑÐ´ÐµÑ ÑабоÑаÑÑ. ÐÐ»Ñ Ð¸ÑÐ¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ Ð´Ð¸Ð½Ð°Ð¼Ð¸ÑеÑкиÑ
команд пÑедÑÑмоÑÑен опеÑаÑÐ¾Ñ EXECUTE:
EXECUTEÑÑÑока-командÑ[ INTO [STRICT]ÑелÑ] [ USINGвÑÑажение[, ... ] ];
где ÑÑÑока-ÐºÐ¾Ð¼Ð°Ð½Ð´Ñ ÑÑо вÑÑажение, ÑоÑмиÑÑÑÑее ÑÑÑÐ¾ÐºÑ (Ñипа text) Ñ ÑекÑÑом командÑ, коÑоÑÑÑ Ð½Ñжно вÑполниÑÑ. ÐеобÑзаÑелÑÐ½Ð°Ñ ÑÐµÐ»Ñ â ÑÑо пеÑеменнаÑ-запиÑÑ, пеÑеменнаÑ-коÑÑеж или ÑазделÑннÑй запÑÑÑми ÑпиÑок пÑоÑÑÑÑ
пеÑеменнÑÑ
и полей запиÑи/коÑÑежа, кÑда бÑдÑÑ Ð¿Ð¾Ð¼ÐµÑÐµÐ½Ñ ÑезÑлÑÑаÑÑ ÐºÐ¾Ð¼Ð°Ð½Ð´Ñ. ÐеобÑзаÑелÑнÑе вÑÑÐ°Ð¶ÐµÐ½Ð¸Ñ Ð² USING ÑоÑмиÑÑÑÑ Ð·Ð½Ð°ÑениÑ, коÑоÑÑе бÑдÑÑ Ð²ÑÑÐ°Ð²Ð»ÐµÐ½Ñ Ð² командÑ.
Ð ÑÑоÑмиÑованном ÑекÑÑе ÐºÐ¾Ð¼Ð°Ð½Ð´Ñ Ð·Ð°Ð¼ÐµÐ½Ð° имÑн пеÑеменнÑÑ PL/pgSQL на Ð¸Ñ Ð·Ð½Ð°ÑÐµÐ½Ð¸Ñ Ð¿ÑоводиÑÑÑÑ Ð½Ðµ бÑдеÑ. ÐÑе Ð½ÐµÐ¾Ð±Ñ Ð¾Ð´Ð¸Ð¼Ñе знаÑÐµÐ½Ð¸Ñ Ð¿ÐµÑеменнÑÑ Ð´Ð¾Ð»Ð¶Ð½Ñ Ð±ÑÑÑ Ð²ÑÑÐ°Ð²Ð»ÐµÐ½Ñ Ð² команднÑÑ ÑÑÑÐ¾ÐºÑ Ð¿Ñи ÐµÑ Ð¿Ð¾ÑÑÑоении, либо нÑжно иÑполÑзоваÑÑ Ð¿Ð°ÑамеÑÑÑ, как опиÑано ниже.
Также, Ð½ÐµÑ Ð½Ð¸ÐºÐ°ÐºÐ¾Ð³Ð¾ плана кеÑиÑÐ¾Ð²Ð°Ð½Ð¸Ñ Ð´Ð»Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´, вÑполнÑемÑÑ
Ñ Ð¿Ð¾Ð¼Ð¾ÑÑÑ EXECUTE. ÐмеÑÑо ÑÑого план ÑоздаÑÑÑÑ ÐºÐ°Ð¶Ð´Ñй Ñаз пÑи вÑполнении. Таким обÑазом, ÑÑÑока ÐºÐ¾Ð¼Ð°Ð½Ð´Ñ Ð¼Ð¾Ð¶ÐµÑ Ð´Ð¸Ð½Ð°Ð¼Ð¸ÑеÑки ÑоздаваÑÑÑÑ Ð²Ð½ÑÑÑи ÑÑнкÑии Ð´Ð»Ñ Ð²ÑÐ¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ Ð´ÐµÐ¹ÑÑвий Ñ ÑазлиÑнÑми ÑаблиÑами и ÑÑолбÑами.
ÐÑедложение INTO ÑказÑваеÑ, кÑда Ð´Ð¾Ð»Ð¶Ð½Ñ Ð±ÑÑÑ Ð¿Ð¾Ð¼ÐµÑÐµÐ½Ñ ÑезÑлÑÑаÑÑ SQL-командÑ, возвÑаÑаÑÑей ÑÑÑоки. ÐÑли иÑполÑзÑеÑÑÑ Ð¿ÐµÑÐµÐ¼ÐµÐ½Ð½Ð°Ñ ÑÑÑокового Ñипа или ÑпиÑок пеÑеменнÑÑ
, Ñо они Ð´Ð¾Ð»Ð¶Ð½Ñ Ð² ÑоÑноÑÑи ÑооÑвеÑÑÑвоваÑÑ ÑÑÑÑкÑÑÑе ÑезÑлÑÑаÑа запÑоÑа (когда иÑполÑзÑеÑÑÑ Ð¿ÐµÑÐµÐ¼ÐµÐ½Ð½Ð°Ñ Ñипа record, она авÑомаÑиÑеÑки пÑиводиÑÑÑ Ðº ÑÑÑÐ¾ÐºÐ¾Ð²Ð¾Ð¼Ñ ÑÐ¸Ð¿Ñ ÑезÑлÑÑаÑа запÑоÑа). ÐÑли возвÑаÑаеÑÑÑ Ð½ÐµÑколÑко ÑÑÑок, Ñо ÑолÑко пеÑÐ²Ð°Ñ Ð±ÑÐ´ÐµÑ Ð¿ÑиÑвоена пеÑеменной(Ñм) в INTO. ÐÑли не возвÑаÑаеÑÑÑ Ð½Ð¸ одной ÑÑÑоки, Ñо пÑиÑваиваеÑÑÑ NULL. Ðез пÑÐµÐ´Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ INTO ÑезÑлÑÑаÑÑ Ð·Ð°Ð¿ÑоÑа оÑбÑаÑÑваÑÑÑÑ.
С Ñказанием STRICT запÑÐ¾Ñ Ð´Ð¾Ð»Ð¶ÐµÐ½ веÑнÑÑÑ Ñовно Ð¾Ð´Ð½Ñ ÑÑÑокÑ, инаÑе вÑдаÑÑÑÑ ÑообÑение об оÑибке.
Ð ÑекÑÑе ÐºÐ¾Ð¼Ð°Ð½Ð´Ñ Ð¼Ð¾Ð¶Ð½Ð¾ иÑполÑзоваÑÑ Ð·Ð½Ð°ÑÐµÐ½Ð¸Ñ Ð¿Ð°ÑамеÑÑов, ÑÑÑлки на паÑамеÑÑÑ Ð¾Ð±Ð¾Ð·Ð½Ð°ÑаÑÑÑÑ ÐºÐ°Ðº $1, $2 и Ñ. д. ÐÑи ÑÐ¸Ð¼Ð²Ð¾Ð»Ñ ÑказÑваÑÑ Ð½Ð° знаÑениÑ, наÑ
одÑÑиеÑÑ Ð² пÑедложении USING. Такой меÑод заÑаÑÑÑÑ Ð¿ÑедпоÑÑиÑелÑнее, Ñем вÑÑавка знаÑений в ÐºÐ¾Ð¼Ð°Ð½Ð´Ñ Ð² виде ÑекÑÑа: он позволÑÐµÑ Ð¸ÑклÑÑиÑÑ Ð²Ð¾ вÑÐµÐ¼Ñ Ð¸ÑÐ¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ Ð´Ð¾Ð¿Ð¾Ð»Ð½Ð¸ÑелÑнÑе ÑаÑÑ
Ð¾Ð´Ñ Ð½Ð° пÑеобÑÐ°Ð·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð·Ð½Ð°Ñений в ÑекÑÑ Ð¸ обÑаÑно, и не оÑкÑÑÐ²Ð°ÐµÑ Ð²Ð¾Ð·Ð¼Ð¾Ð¶Ð½Ð¾ÑÑи Ð´Ð»Ñ SQL-инÑекÑий, не ÑÑебÑÑ Ð¿ÑименÑÑÑ ÑкÑаниÑование или кавÑÑки Ð´Ð»Ñ ÑпеÑÑимволов. ÐÑимеÑ:
EXECUTE 'SELECT count(*) FROM mytable WHERE inserted_by = $1 AND inserted <= $2' INTO c USING checked_user, checked_date;
ÐбÑаÑиÑе внимание, ÑÑо ÑÐ¸Ð¼Ð²Ð¾Ð»Ñ Ð¿Ð°ÑамеÑÑов можно иÑполÑзоваÑÑ ÑолÑко вмеÑÑо знаÑений даннÑÑ . ÐÑли же ÑÑебÑеÑÑÑ Ð´Ð¸Ð½Ð°Ð¼Ð¸ÑеÑки ÑоÑмиÑоваÑÑ Ð¸Ð¼ÐµÐ½Ð° ÑÐ°Ð±Ð»Ð¸Ñ Ð¸Ð»Ð¸ ÑÑолбÑов, Ð¸Ñ Ð½ÐµÐ¾Ð±Ñ Ð¾Ð´Ð¸Ð¼Ð¾ вÑÑавлÑÑÑ Ð² виде ÑекÑÑа. ÐапÑимеÑ, еÑли в пÑедÑдÑÑем запÑоÑе Ð½ÐµÐ¾Ð±Ñ Ð¾Ð´Ð¸Ð¼Ð¾ динамиÑеÑки задаваÑÑ Ð¸Ð¼Ñ ÑаблиÑÑ, можно ÑделаÑÑ ÑледÑÑÑее:
EXECUTE 'SELECT count(*) FROM '
|| quote_ident(tabname)
|| ' WHERE inserted_by = $1 AND inserted <= $2'
INTO c
USING checked_user, checked_date; РкаÑеÑÑве более аккÑÑаÑного ÑеÑениÑ, вмеÑÑо имени ÑÐ°Ð±Ð»Ð¸Ñ Ð¸Ð»Ð¸ ÑÑолбÑов можно иÑполÑзоваÑÑ Ñказание ÑоÑмаÑа %I Ñ ÑÑнкÑией format() (ÑекÑÑ, ÑазделÑннÑй Ñимволами новой ÑÑÑоки, ÑоединÑеÑÑÑ Ð²Ð¼ÐµÑÑе):
EXECUTE format('SELECT count(*) FROM %I '
'WHERE inserted_by = $1 AND inserted <= $2', tabname)
INTO c
USING checked_user, checked_date; ÐÑÑ Ð¾Ð´Ð½Ð¾ огÑаниÑение ÑоÑÑÐ¾Ð¸Ñ Ð² Ñом, ÑÑо ÑÐ¸Ð¼Ð²Ð¾Ð»Ñ Ð¿Ð°ÑамеÑÑов могÑÑ Ð¸ÑполÑзоваÑÑÑÑ ÑолÑко в командаÑ
SELECT, INSERT, UPDATE и DELETE. РопеÑаÑоÑÑ Ð´ÑÑгиÑ
Ñипов (обÑÑно назÑваемÑе ÑлÑжебнÑми) знаÑÐµÐ½Ð¸Ñ Ð½Ñжно вÑÑавлÑÑÑ Ð² ÑекÑÑовом виде, даже еÑли ÑÑо пÑоÑÑо знаÑÐµÐ½Ð¸Ñ Ð´Ð°Ð½Ð½ÑÑ
.
Ðоманда EXECUTE c неизменÑемÑм ÑекÑÑом и паÑамеÑÑами USING (как в пеÑвом пÑимеÑе вÑÑе), ÑÑнкÑионалÑно ÑквиваленÑна команде, запиÑанной напÑÑмÑÑ Ð² PL/pgSQL, в коÑоÑой пеÑеменнÑе PL/pgSQL авÑомаÑиÑеÑки заменÑÑÑÑÑ Ð·Ð½Ð°ÑениÑми. Ðажное оÑлиÑие в Ñом, ÑÑо EXECUTE пÑи каждом иÑполнении заново ÑÑÑÐ¾Ð¸Ñ Ð¿Ð»Ð°Ð½ ÐºÐ¾Ð¼Ð°Ð½Ð´Ñ Ñ ÑÑÑÑом ÑекÑÑиÑ
знаÑений паÑамеÑÑов, Ñогда как PL/pgSQL ÑÑÑÐ¾Ð¸Ñ Ð¾Ð±Ñий план вÑÐ¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ Ð¸ кеÑиÑÑÐµÑ ÐµÐ³Ð¾ пÑи повÑоÑном иÑполÑзовании. Ð ÑеÑ
ÑлÑÑаÑÑ
, когда наилÑÑÑий план вÑÐ¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ ÑилÑно завиÑÐ¸Ñ Ð¾Ñ Ð·Ð½Ð°Ñений паÑамеÑÑов, Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð¿Ð¾Ð»ÐµÐ·Ð½Ð¾ иÑполÑзоваÑÑ EXECUTE Ð´Ð»Ñ Ð³Ð°ÑанÑии Ñого, ÑÑо не бÑÐ´ÐµÑ Ð²ÑбÑан обÑий план.
РнаÑÑоÑÑее вÑÐµÐ¼Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð° SELECT INTO не поддеÑживаеÑÑÑ Ð² EXECUTE, вмеÑÑо ÑÑого нÑжно вÑполнÑÑÑ Ð¾Ð±ÑÑнÑй SELECT и ÑказаÑÑ INTO Ð´Ð»Ñ Ñамой ÐºÐ¾Ð¼Ð°Ð½Ð´Ñ EXECUTE.
ÐÑимеÑание
ÐпеÑаÑÐ¾Ñ EXECUTE в PL/pgSQL не Ð¸Ð¼ÐµÐµÑ Ð¾ÑноÑÐµÐ½Ð¸Ñ Ðº одноимÑÐ½Ð½Ð¾Ð¼Ñ SQL-опеÑаÑоÑÑ ÑеÑвеÑа Postgres Pro. СеÑвеÑнÑй EXECUTE не Ð¼Ð¾Ð¶ÐµÑ Ð½Ð°Ð¿ÑÑмÑÑ Ð¸ÑполÑзоваÑÑÑÑ Ð² ÑÑнкÑиÑÑ
на PL/pgSQL (и в ÑÑом Ð½ÐµÑ Ð½ÐµÐ¾Ð±Ñ
одимоÑÑи).
ÐÑÐ¸Ð¼ÐµÑ 39.1. ÐÑполÑзование кавÑÑек в динамиÑеÑÐºÐ¸Ñ Ð·Ð°Ð¿ÑоÑаÑ
ÐÑи ÑабоÑе Ñ Ð´Ð¸Ð½Ð°Ð¼Ð¸ÑеÑкими командами ÑаÑÑо пÑÐ¸Ñ Ð¾Ð´Ð¸ÑÑÑ Ð¸Ð¼ÐµÑÑ Ð´ÐµÐ»Ð¾ Ñ ÑкÑаниÑованием одинаÑнÑÑ ÐºÐ°Ð²ÑÑек. РекомендÑемÑм меÑодом Ð´Ð»Ñ Ð²Ð·ÑÑÐ¸Ñ ÑекÑÑа в кавÑÑки в Ñеле ÑÑнкÑии ÑвлÑеÑÑÑ ÑкÑаниÑование знаками доллаÑа. (ÐÑли имееÑÑÑ ÑнаÑледованнÑй код, не иÑполÑзÑÑÑий ÑÑÐ¾Ñ Ð¼ÐµÑод, пожалÑйÑÑа, обÑаÑиÑеÑÑ Ðº обзоÑÑ Ð² ÐодÑазделе 39.11.1, ÑÑо Ð¿Ð¾Ð¼Ð¾Ð¶ÐµÑ ÑÑкономиÑÑ ÑÑÐ¸Ð»Ð¸Ñ Ð¿Ñи пеÑеводе кода к более пÑÐ¸ÐµÐ¼Ð»ÐµÐ¼Ð¾Ð¼Ñ Ð²Ð¸Ð´Ñ.)
ÐинамиÑеÑкие знаÑÐµÐ½Ð¸Ñ ÑÑебÑÑÑ Ð¾Ñобого вниманиÑ, Ñак как они могÑÑ ÑодеÑжаÑÑ Ð°Ð¿Ð¾ÑÑÑоÑÑ. ÐапÑимеÑ, можно иÑполÑзоваÑÑ ÑÑнкÑÐ¸Ñ format() (пÑедполагаеÑÑÑ, ÑÑо Ñело ÑÑнкÑии заклÑÑаеÑÑÑ Ð² доллаÑÑ, Ñак ÑÑо апоÑÑÑоÑÑ Ð´ÑблиÑоваÑÑ Ð½Ðµ нÑжно):
EXECUTE format('UPDATE tbl SET %I = $1 '
'WHERE key = $2', colname) USING newvalue, keyvalue;Также можно напÑÑмÑÑ Ð²ÑзÑваÑÑ ÑÑнкÑии заклÑÑÐµÐ½Ð¸Ñ Ð² кавÑÑки:
EXECUTE 'UPDATE tbl SET '
|| quote_ident(colname)
|| ' = '
|| quote_literal(newvalue)
|| ' WHERE key = '
|| quote_literal(keyvalue);ÐÑÐ¾Ñ Ð¿ÑÐ¸Ð¼ÐµÑ Ð´ÐµÐ¼Ð¾Ð½ÑÑÑиÑÑÐµÑ Ð¸ÑполÑзование ÑÑнкÑий quote_ident и quote_literal (Ñм. Раздел 9.4). ÐÐ»Ñ Ð½Ð°Ð´ÑжноÑÑи, вÑÑажениÑ, ÑодеÑжаÑие иденÑиÑикаÑоÑÑ ÑÑолбÑов и ÑÐ°Ð±Ð»Ð¸Ñ Ð´Ð¾Ð»Ð¶Ð½Ñ Ð¸ÑполÑзоваÑÑ ÑÑнкÑÐ¸Ñ quote_ident пÑи добавлении в ÑекÑÑ Ð·Ð°Ð¿ÑоÑа. Ð Ð´Ð»Ñ Ð²ÑÑажений Ñо знаÑениÑми, коÑоÑÑе Ð´Ð¾Ð»Ð¶Ð½Ñ Ð±ÑÑÑ Ð¾Ð±ÑÑнÑми ÑÑÑоками, иÑполÑзÑеÑÑÑ ÑÑнкÑÐ¸Ñ quote_literal. ÐÑи ÑÑнкÑии вÑполнÑÑÑ ÑооÑвеÑÑÑвÑÑÑие Ñаги, ÑÑÐ¾Ð±Ñ Ð²ÐµÑнÑÑÑ ÑекÑÑ, по ÑиÑÑаÑии заклÑÑÑннÑй в двойнÑе или одинаÑнÑе кавÑÑки и Ñ Ð¿ÑавилÑно ÑкÑаниÑованнÑми ÑпеÑиалÑнÑми Ñимволами.
Так как ÑÑнкÑÐ¸Ñ quote_literal помеÑена как STRICT, Ñо она вÑегда возвÑаÑÐ°ÐµÑ NULL, еÑли пеÑеданнÑй ей аÑгÑÐ¼ÐµÐ½Ñ Ð¸Ð¼ÐµÐµÑ Ð·Ð½Ð°Ñение NULL. РпÑиведÑнном вÑÑе пÑимеÑе, еÑли newvalue или keyvalue бÑли NULL, вÑÑ ÑÑÑока Ñ ÑекÑÑом запÑоÑа ÑÑÐ°Ð½ÐµÑ NULL, ÑÑо пÑиведÑÑ Ðº оÑибке в EXECUTE. ÐÐ»Ñ Ð¿ÑедоÑвÑаÑÐµÐ½Ð¸Ñ ÑÑой пÑÐ¾Ð±Ð»ÐµÐ¼Ñ Ð¸ÑполÑзÑйÑе ÑÑнкÑÐ¸Ñ quote_nullable, коÑоÑÐ°Ñ ÑабоÑÐ°ÐµÑ Ñак же, как quote_literal за иÑклÑÑением Ñого, ÑÑо пÑи вÑзове Ñ Ð¿ÑÑÑÑм аÑгÑменÑом возвÑаÑÐ°ÐµÑ ÑÑÑÐ¾ÐºÑ 'NULL'. ÐапÑимеÑ:
EXECUTE 'UPDATE tbl SET '
|| quote_ident(colname)
|| ' = '
|| quote_nullable(newvalue)
|| ' WHERE key = '
|| quote_nullable(keyvalue); ÐÑли Ð²Ñ Ð¸Ð¼ÐµÐµÑе дело Ñо знаÑениÑми, коÑоÑÑе могÑÑ Ð±ÑÑÑ Ð¿ÑÑÑÑми, Ñо, как пÑавило, нÑжно иÑполÑзоваÑÑ quote_nullable вмеÑÑо quote_literal.
Ðак обÑÑно, необÑ
одимо ÑбедиÑÑÑÑ, ÑÑо знаÑÐµÐ½Ð¸Ñ NULL в запÑоÑе не пÑинеÑÑÑ Ð½ÐµÐ¾Ð¶Ð¸Ð´Ð°Ð½Ð½ÑÑ
ÑезÑлÑÑаÑов. ÐапÑимеÑ, ÑледÑÑÑее ÑÑловие WHERE
'WHERE key = ' || quote_nullable(keyvalue)
никогда не вÑполниÑÑÑ, еÑли keyvalue â NULL, Ñак как пÑименение = Ñ Ð¾Ð¿ÐµÑандом, имеÑÑим знаÑение NULL, вÑегда даÑÑ NULL. ÐÑли ÑÑебÑеÑÑÑ, ÑÑÐ¾Ð±Ñ NULL обÑабаÑÑвалоÑÑ ÐºÐ°Ðº обÑÑное знаÑение, Ñо ÑÑловие вÑÑе нÑжно пеÑепиÑаÑÑ Ñак:
'WHERE key IS NOT DISTINCT FROM ' || quote_nullable(keyvalue)
(РнаÑÑоÑÑее вÑÐµÐ¼Ñ IS NOT DISTINCT FROM ÑабоÑÐ°ÐµÑ Ð¼ÐµÐ½ÐµÐµ ÑÑÑекÑивно, Ñем =, Ñак ÑÑо иÑполÑзÑйÑе ÑÑÐ¾Ñ ÑпоÑоб, ÑолÑко еÑли ÑÑо дейÑÑвиÑелÑно необÑ
одимо. ÐодÑобнее оÑобенноÑÑи NULL и IS DISTINCT опиÑÐ°Ð½Ñ Ð² Разделе 9.2.)
ÐбÑаÑиÑе внимание, ÑÑо иÑполÑзование знака $ полезно ÑолÑко Ð´Ð»Ñ Ð²Ð·ÑÑÐ¸Ñ Ð² кавÑÑки ÑикÑиÑованного ÑекÑÑа. ÐÐ»Ð¾Ñ Ð°Ñ Ð¸Ð´ÐµÑ Ð½Ð°Ð¿Ð¸ÑаÑÑ ÑÑÐ¾Ñ Ð¿ÑÐ¸Ð¼ÐµÑ Ñак:
EXECUTE 'UPDATE tbl SET '
|| quote_ident(colname)
|| ' = $$'
|| newvalue
|| '$$ WHERE key = '
|| quote_literal(keyvalue); поÑÐ¾Ð¼Ñ ÑÑо newvalue Ð¼Ð¾Ð¶ÐµÑ Ñакже ÑодеÑжаÑÑ $$. ÐÑа же пÑоблема Ð¼Ð¾Ð¶ÐµÑ Ð²Ð¾Ð·Ð½Ð¸ÐºÐ½ÑÑÑ Ð¸ Ñ Ð»ÑбÑм дÑÑгим ÑазделиÑелем, иÑполÑзÑемÑм поÑле знака $. ÐоÑÑомÑ, ÑÑÐ¾Ð±Ñ Ð±ÐµÐ·Ð¾Ð¿Ð°Ñно заклÑÑиÑÑ Ð·Ð°Ñанее неизвеÑÑнÑй ÑекÑÑ Ð² кавÑÑки, нÑжно иÑполÑзоваÑÑ ÑооÑвеÑÑÑвÑÑÑие ÑÑнкÑии: quote_literal, quote_nullable, или quote_ident.
ÐинамиÑеÑкие опеÑаÑоÑÑ SQL Ñакже можно безопаÑно ÑÑоÑмиÑоваÑÑ, иÑполÑзÑÑ ÑÑнкÑÐ¸Ñ format (Ñм. Раздел 9.4). ÐапÑимеÑ:
EXECUTE format('UPDATE tbl SET %I = %L '
'WHERE key = %L', colname, newvalue, keyvalue); Указание %I ÑавнознаÑно вÑÐ·Ð¾Ð²Ñ quote_ident, а %L â вÑÐ·Ð¾Ð²Ñ quote_nullable. ФÑнкÑÐ¸Ñ format Ð¼Ð¾Ð¶ÐµÑ Ð¿ÑименÑÑÑÑÑ Ð² ÑоÑеÑании Ñ Ð¿Ñедложением USING:
EXECUTE format('UPDATE tbl SET %I = $1 WHERE key = $2', colname)
USING newvalue, keyvalue; ÐÑа ÑоÑма лÑÑÑе, Ñак как Ñ Ð½ÐµÐ¹ пеÑеменнÑе обÑабаÑÑваÑÑÑÑ Ð² иÑ
ÑобÑÑвенном ÑоÑмаÑе даннÑÑ
, а не пÑеобÑазÑÑÑÑÑ Ð±ÐµÐ·ÑÑловно в ÑекÑÑ, ÑÑÐ¾Ð±Ñ Ð·Ð°Ñем вÑводиÑÑÑÑ Ñ Ð¸ÑполÑзованием %L. Ðна Ñакже и более ÑÑÑекÑивна.
Ðолее обÑÑмнÑй пÑÐ¸Ð¼ÐµÑ Ð¸ÑполÑÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð´Ð¸Ð½Ð°Ð¼Ð¸ÑеÑкой ÐºÐ¾Ð¼Ð°Ð½Ð´Ñ Ð¸ EXECUTE можно ÑвидеÑÑ Ð² ÐÑимеÑе 39.9. РнÑм ÑоздаÑÑÑÑ Ð¸ динамиÑеÑки вÑполнÑеÑÑÑ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð° CREATE FUNCTION Ð´Ð»Ñ Ð¾Ð¿ÑÐµÐ´ÐµÐ»ÐµÐ½Ð¸Ñ Ð½Ð¾Ð²Ð¾Ð¹ ÑÑнкÑии.
39.5.5. СÑаÑÑÑ Ð²ÑÐ¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ñ
ÐпÑеделиÑÑ ÑезÑлÑÑÐ°Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ñ Ð¼Ð¾Ð¶Ð½Ð¾ неÑколÑкими ÑпоÑобами. Ðо-пеÑвÑÑ
, можно воÑполÑзоваÑÑÑÑ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð¾Ð¹ GET DIAGNOSTICS, имеÑÑей ÑоÑмÑ:
GET [ CURRENT ] DIAGNOSTICSпеÑеменнаÑ{ = | := }ÑлеменÑ[ , ... ];
ÐÑа команда позволÑÐµÑ Ð¿Ð¾Ð»ÑÑиÑÑ ÑиÑÑемнÑе индикаÑоÑÑ ÑоÑÑоÑниÑ. Слово CURRENT не неÑÑÑ ÑмÑÑловой нагÑÑзки (но Ñм. Ñакже опиÑание GET STACKED DIAGNOSTICS в ÐодÑазделе 39.6.6.1). ÐаждÑй ÑÐ»ÐµÐ¼ÐµÐ½Ñ Ð¿ÑедÑÑавлÑеÑÑÑ ÐºÐ»ÑÑевÑм Ñловом, ÑказÑваÑÑим, какое знаÑение ÑоÑÑоÑÐ½Ð¸Ñ Ð½Ñжно пÑиÑвоиÑÑ Ð·Ð°Ð´Ð°Ð½Ð½Ð¾Ð¹ пеÑеменной (она должна имеÑÑ Ð¿Ð¾Ð´Ñ
одÑÑий Ñип даннÑÑ
, ÑÑÐ¾Ð±Ñ Ð¿ÑинÑÑÑ ÐµÐ³Ð¾). ÐоÑÑÑпнÑе в наÑÑоÑÑее вÑÐµÐ¼Ñ ÑлеменÑÑ ÑоÑÑоÑÐ½Ð¸Ñ Ð¿Ð¾ÐºÐ°Ð·Ð°Ð½Ñ Ð² ТаблиÑе 39.1. ÐмеÑÑо пÑинÑÑого в ÑÑандаÑÑе SQL пÑиÑÐ²Ð°Ð¸Ð²Ð°Ð½Ð¸Ñ (=) можно пÑименÑÑÑ Ð¿ÑиÑваивание Ñ Ð´Ð²Ð¾ÐµÑоÑием (:=). ÐапÑимеÑ:
GET DIAGNOSTICS integer_var = ROW_COUNT;
ТаблиÑа 39.1. ÐоÑÑÑпнÑе ÑлеменÑÑ Ð´Ð¸Ð°Ð³Ð½Ð¾ÑÑики
| ÐÐ¼Ñ | Тип | ÐпиÑание |
|---|---|---|
ROW_COUNT | bigint | ÑиÑло ÑÑÑок, обÑабоÑаннÑÑ Ð¿Ð¾Ñледней командой SQL |
RESULT_OID | oid | OID поÑледней ÑÑÑоки, вÑÑавленной пÑедÑдÑÑей командой SQL (полезен ÑолÑко поÑле ÐºÐ¾Ð¼Ð°Ð½Ð´Ñ INSERT Ð´Ð»Ñ ÑаблиÑÑ, ÑодеÑжаÑей OID) |
PG_CONTEXT | text | ÑÑÑоки ÑекÑÑа, опиÑÑваÑÑие ÑекÑÑий ÑÑек вÑзовов (Ñм. ÐодÑаздел 39.6.7) |
ÐÑоÑой ÑпоÑоб опÑÐµÐ´ÐµÐ»ÐµÐ½Ð¸Ñ ÑÑаÑÑÑа вÑÐ¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ñ Ð·Ð°ÐºÐ»ÑÑаеÑÑÑ Ð² пÑовеÑке знаÑÐµÐ½Ð¸Ñ ÑпеÑиалÑной пеÑеменной FOUND, имеÑÑей Ñип boolean. ÐÑи вÑзове ÑÑнкÑии на PL/pgSQL, пеÑÐµÐ¼ÐµÐ½Ð½Ð°Ñ FOUND иниÑиализиÑÑеÑÑÑ Ð² ложÑ. Ðалее, знаÑение пеÑеменной изменÑеÑÑÑ ÑледÑÑÑими опеÑаÑоÑами:
SELECT INTOзапиÑÑÐ²Ð°ÐµÑ Ð²FOUNDtrue, еÑли ÑÑÑока пÑиÑвоена, или false, еÑли ÑÑÑоки не бÑли полÑÑенÑ.PERFORMзапиÑÑÐ²Ð°ÐµÑ Ð²FOUNDtrue, еÑли ÑÑÑоки вÑбÑÐ°Ð½Ñ (и оÑбÑоÑенÑ) или false, еÑли ÑÑÑоки не вÑбÑанÑ.UPDATE,INSERTиDELETEзапиÑÑваÑÑ Ð²FOUNDtrue, еÑли пÑи Ð¸Ñ Ð²Ñполнении бÑла задейÑÑвована Ñ Ð¾ÑÑ Ð±Ñ Ð¾Ð´Ð½Ð° ÑÑÑока, или false, еÑли ни одна ÑÑÑока не бÑла задейÑÑвована.FETCHзапиÑÑваÑÑ Ð²FOUNDtrue, еÑли команда веÑнÑла ÑÑÑокÑ, или false, еÑли ÑÑÑока не вÑбÑана.MOVEзапиÑÑваÑÑ Ð²FOUNDtrue пÑи ÑÑпеÑном пеÑемеÑении кÑÑÑоÑа, в пÑоÑивном ÑлÑÑае â false.FOR, как иFOREACH, запиÑÑÐ²Ð°ÐµÑ Ð²FOUNDtrue, еÑли бÑла пÑоизведена Ñ Ð¾ÑÑ Ð±Ñ Ð¾Ð´Ð½Ð° иÑеÑаÑÐ¸Ñ Ñикла, в пÑоÑивном ÑлÑÑае â false. ÐÑи ÑÑом знаÑениеFOUNDбÑÐ´ÐµÑ ÑÑÑановлено ÑолÑко поÑле вÑÑ Ð¾Ð´Ð° из Ñикла. Ðока Ñикл вÑполнÑеÑÑÑ, опеÑаÑÐ¾Ñ Ñикла не изменÑÐµÑ Ð·Ð½Ð°Ñение пеÑеменной. Ðо дÑÑгие опеÑаÑоÑÑ Ð²Ð½ÑÑÑи Ñикла могÑÑ Ð¼ÐµÐ½ÑÑÑ Ð·Ð½Ð°ÑениеFOUND.RETURN QUERYиRETURN QUERY EXECUTEзапиÑÑваÑÑ Ð²FOUNDtrue, еÑли запÑÐ¾Ñ Ð²ÐµÑнÑл Ñ Ð¾ÑÑ Ð±Ñ Ð¾Ð´Ð½Ñ ÑÑÑокÑ, или false, еÑли ÑÑÑоки не вÑбÑанÑ.
ÐÑÑгие опеÑаÑоÑÑ PL/pgSQL не менÑÑÑ Ð·Ð½Ð°Ñение FOUND. ÐомниÑе в ÑаÑÑноÑÑи, ÑÑо EXECUTE изменÑÐµÑ Ð²Ñвод GET DIAGNOSTICS, но не менÑÐµÑ FOUND.
FOUND ÑвлÑеÑÑÑ Ð»Ð¾ÐºÐ°Ð»Ñной пеÑеменной в каждой ÑÑнкÑии PL/pgSQL и лÑбÑе ÐµÑ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ, влиÑÑÑ ÑолÑко на ÑекÑÑÑÑ ÑÑнкÑиÑ.
39.5.6. Ðе делаÑÑ Ð½Ð¸Ñего
Ðногда бÑÐ²Ð°ÐµÑ Ð¿Ð¾Ð»ÐµÐ·ÐµÐ½ опеÑаÑоÑ, коÑоÑÑй не Ð´ÐµÐ»Ð°ÐµÑ Ð½Ð¸Ñего. ÐапÑимеÑ, он Ð¼Ð¾Ð¶ÐµÑ Ð¿Ð¾ÐºÐ°Ð·ÑваÑÑ, ÑÑо одна из веÑвей 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 не допÑÑкаÑÑÑÑ Ð¿ÑÑÑÑе ÑпиÑки опеÑаÑоÑов, поÑÑÐ¾Ð¼Ñ NULL обÑзаÑелен в подобнÑÑ
ÑиÑÑаÑиÑÑ
. Ð PL/pgSQL ÑазÑеÑаеÑÑÑ Ð½Ðµ пиÑаÑÑ Ð½Ð¸Ñего.