36.5. ФÑнкÑии на ÑзÑке запÑоÑов (SQL) #
- 36.5.1. ÐÑгÑменÑÑ SQL-ÑÑнкÑий
- 36.5.2. ФÑнкÑии SQL Ñ Ð±Ð°Ð·Ð¾Ð²Ñми Ñипами
- 36.5.3. ФÑнкÑии SQL Ñ ÑоÑÑавнÑми Ñипами
- 36.5.4. ФÑнкÑии SQL Ñ Ð²ÑÑ Ð¾Ð´Ð½Ñми паÑамеÑÑами
- 36.5.5. ÐÑоÑедÑÑÑ SQL Ñ Ð²ÑÑ Ð¾Ð´Ð½Ñми паÑамеÑÑами
- 36.5.6. ФÑнкÑии SQL Ñ Ð¿ÐµÑеменнÑм ÑиÑлом аÑгÑменÑов
- 36.5.7. ФÑнкÑии SQL Ñо знаÑениÑми аÑгÑменÑов по ÑмолÑаниÑ
- 36.5.8. ФÑнкÑии SQL, поÑождаÑÑие ÑаблиÑÑ
- 36.5.9. ФÑнкÑии SQL, возвÑаÑаÑÑие множеÑÑва
- 36.5.10. ФÑнкÑии SQL, возвÑаÑаÑÑие ÑаблиÑÑ (
TABLE)- 36.5.11. ÐолимоÑÑнÑе ÑÑнкÑии SQL
- 36.5.12. ФÑнкÑии SQL Ñ Ð¿Ñавилами ÑоÑÑиÑовки
- 36.5.2. ФÑнкÑии SQL Ñ Ð±Ð°Ð·Ð¾Ð²Ñми Ñипами
SQL-ÑÑнкÑии вÑполнÑÑÑ Ð¿ÑоизволÑнÑй ÑпиÑок опеÑаÑоÑов SQL и возвÑаÑаÑÑ ÑезÑлÑÑÐ°Ñ Ð¿Ð¾Ñледнего запÑоÑа в ÑпиÑке. РпÑоÑÑом ÑлÑÑае (не Ñ Ð¼Ð½Ð¾Ð¶ÐµÑÑвом) бÑÐ´ÐµÑ Ð²Ð¾Ð·Ð²ÑаÑена пеÑÐ²Ð°Ñ ÑÑÑока ÑезÑлÑÑаÑа поÑледнего запÑоÑа. (ÐомниÑе, ÑÑо понÑÑие «пеÑÐ²Ð°Ñ ÑÑÑока» в набоÑе ÑезÑлÑÑаÑов Ñ Ð½ÐµÑколÑкими ÑÑÑоками опÑеделено ÑоÑно, ÑолÑко еÑли пÑиÑÑÑÑÑвÑÐµÑ ORDER BY.) ÐÑли поÑледний запÑÐ¾Ñ Ð²Ð¾Ð¾Ð±Ñе не веÑнÑÑ ÑÑÑоки, бÑÐ´ÐµÑ Ð²Ð¾Ð·Ð²ÑаÑено знаÑение NULL.
ÐÑоме Ñого, можно обÑÑвиÑÑ SQL-ÑÑнкÑÐ¸Ñ ÐºÐ°Ðº возвÑаÑаÑÑÑÑ Ð¼Ð½Ð¾Ð¶ÐµÑÑво (Ñо еÑÑÑ, неÑколÑко ÑÑÑок), Ñказав в каÑеÑÑве возвÑаÑаемого Ñипа ÑÑнкÑии SETOF , либо обÑÑвив ÐµÑ Ñ Ñказанием некий_ÑипRETURNS TABLE(. Ð ÑÑом ÑлÑÑае бÑдÑÑ Ð²Ð¾Ð·Ð²ÑаÑÐµÐ½Ñ Ð²Ñе ÑÑÑоки ÑезÑлÑÑаÑа поÑледнего запÑоÑа. ÐодÑобнее ÑÑо опиÑÑваеÑÑÑ Ð½Ð¸Ð¶Ðµ.ÑÑолбÑÑ)
Тело SQL-ÑÑнкÑии должно пÑедÑÑавлÑÑÑ Ñобой ÑпиÑок SQL-опеÑаÑоÑов, ÑазделÑннÑÑ
ÑоÑкой Ñ Ð·Ð°Ð¿ÑÑой. ТоÑка Ñ Ð·Ð°Ð¿ÑÑой поÑле поÑледнего опеÑаÑоÑа Ð¼Ð¾Ð¶ÐµÑ Ð¾ÑÑÑÑÑÑвоваÑÑ. ÐÑли ÑолÑко ÑÑнкÑÐ¸Ñ Ð½Ðµ обÑÑвлена как возвÑаÑаÑÑÐ°Ñ void, поÑледним опеÑаÑоÑом должен бÑÑÑ SELECT, либо INSERT, UPDATE, DELETE или MERGE Ñ Ð¿Ñедложением RETURNING.
ÐÑбой Ð½Ð°Ð±Ð¾Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´ на ÑзÑке SQL можно ÑкомпоноваÑÑ Ð²Ð¼ÐµÑÑе и обознаÑиÑÑ ÐºÐ°Ðº ÑÑнкÑиÑ. Ðомимо запÑоÑов SELECT, ÑÑи ÐºÐ¾Ð¼Ð°Ð½Ð´Ñ Ð¼Ð¾Ð³ÑÑ Ð²ÐºÐ»ÑÑаÑÑ Ð·Ð°Ð¿ÑоÑÑ, изменÑÑÑие даннÑе (INSERT, UPDATE и DELETE и MERGE), а Ñакже дÑÑгие SQL-командÑ. (Ð SQL-ÑÑнкÑиÑÑ
нелÑÐ·Ñ Ð¸ÑполÑзоваÑÑ ÐºÐ¾Ð¼Ð°Ð½Ð´Ñ ÑпÑÐ°Ð²Ð»ÐµÐ½Ð¸Ñ ÑÑанзакÑиÑми, напÑÐ¸Ð¼ÐµÑ COMMIT, SAVEPOINT, и некоÑоÑÑе вÑпомогаÑелÑнÑе командÑ, в ÑаÑÑноÑÑи VACUUM.) Ðднако поÑледней командой должна бÑÑÑ SELECT или команда Ñ Ð¿Ñедложением RETURNING, возвÑаÑаÑÑÐ°Ñ ÑезÑлÑÑÐ°Ñ Ñ Ñипом возвÑаÑа ÑÑнкÑии. ÐÑли же Ð²Ñ Ñ
оÑиÑе опÑеделиÑÑ ÑÑнкÑÐ¸Ñ SQL, вÑполнÑÑÑÑÑ Ð´ÐµÐ¹ÑÑвиÑ, но не возвÑаÑаÑÑÑÑ Ð¿Ð¾Ð»ÐµÐ·Ð½Ð¾Ðµ знаÑение, Ð²Ñ Ð¼Ð¾Ð¶ÐµÑе обÑÑвиÑÑ ÐµÑ ÐºÐ°Ðº возвÑаÑаÑÑÑÑ Ñип void. ÐапÑимеÑ, ÑÑа ÑÑнкÑÐ¸Ñ ÑдалÑÐµÑ ÑÑÑоки Ñ Ð¾ÑÑиÑаÑелÑнÑм жалованÑем из ÑаблиÑÑ emp:
CREATE FUNCTION clean_emp() RETURNS void AS '
DELETE FROM emp
WHERE salary < 0;
' LANGUAGE SQL;
SELECT clean_emp();
clean_emp
-----------
(1 row)
ÐÑли запиÑаÑÑ Ñо же Ñамое в виде пÑоÑедÑÑÑ, Ñо можно не ÑказÑваÑÑ Ð²Ð¾Ð·Ð²ÑаÑаемÑй Ñип. ÐапÑимеÑ:
CREATE PROCEDURE clean_emp() AS '
DELETE FROM emp
WHERE salary < 0;
' LANGUAGE SQL;
CALL clean_emp();
Ð ÑакиÑ
пÑоÑÑÑÑ
ÑлÑÑаÑÑ
ÑазниÑа Ð¼ÐµÐ¶Ð´Ñ Ð¿ÑоÑедÑÑой и ÑÑнкÑией, возвÑаÑаÑÑей void, в оÑновном ÑÑилиÑÑиÑеÑкаÑ. Ðднако по ÑÑÐ°Ð²Ð½ÐµÐ½Ð¸Ñ Ñ ÑÑнкÑиÑми пÑоÑедÑÑÑ Ð¿ÑедоÑÑавлÑÑÑ Ð´Ð¾Ð¿Ð¾Ð»Ð½Ð¸ÑелÑнÑÑ ÑÑнкÑионалÑноÑÑÑ, напÑÐ¸Ð¼ÐµÑ Ð²Ð¾Ð·Ð¼Ð¾Ð¶Ð½Ð¾ÑÑи ÑпÑÐ°Ð²Ð»ÐµÐ½Ð¸Ñ ÑÑанзакÑиÑми. ÐÑоме Ñого, пÑоÑедÑÑÑ ÑооÑвеÑÑÑвÑÑÑ ÑÑандаÑÑÑ SQL, а возвÑаÑаÑÑие void ÑÑнкÑии ÑпеÑиÑиÑÐ½Ñ Ð´Ð»Ñ PostgreSQL.
СинÑакÑÐ¸Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ñ CREATE FUNCTION ÑÑебÑеÑ, ÑÑÐ¾Ð±Ñ Ñело ÑÑнкÑии бÑло запиÑано как ÑÑÑÐ¾ÐºÐ¾Ð²Ð°Ñ ÐºÐ¾Ð½ÑÑанÑа. ÐбÑÑно Ð´Ð»Ñ ÑÑого Ñдобнее вÑего заклÑÑаÑÑ ÑÑÑоковÑÑ ÐºÐ¾Ð½ÑÑанÑÑ Ð² доллаÑÑ (Ñм. ÐодÑаздел 4.1.2.4). ÐÑли Ð²Ñ ÑеÑиÑе иÑполÑзоваÑÑ Ð¾Ð±ÑÑнÑй ÑинÑакÑÐ¸Ñ Ñ Ð·Ð°ÐºÐ»ÑÑением ÑÑÑоки в апоÑÑÑоÑÑ, вам пÑидÑÑÑÑ Ð´ÑблиÑоваÑÑ Ð°Ð¿Ð¾ÑÑÑоÑÑ (') и обÑаÑнÑÑ ÐºÐ¾ÑÑÑ ÑеÑÑÑ (\) (пÑедполагаеÑÑÑ ÑинÑакÑÐ¸Ñ ÑпеÑпоÑледоваÑелÑноÑÑей) в Ñеле ÑÑнкÑии (Ñм. ÐодÑаздел 4.1.2.1).
36.5.1. ÐÑгÑменÑÑ SQL-ÑÑнкÑий #
РаÑгÑменÑам SQL-ÑÑнкÑии можно обÑаÑаÑÑÑÑ Ð² Ñеле ÑÑнкÑии по именам или номеÑам. Ðиже пÑÐ¸Ð²ÐµÐ´ÐµÐ½Ñ Ð¿ÑимеÑÑ Ð¾Ð±Ð¾Ð¸Ñ Ð²Ð°ÑианÑов.
ЧÑÐ¾Ð±Ñ Ð¸ÑполÑзоваÑÑ Ð¸Ð¼Ñ, обÑÑвиÑе аÑгÑÐ¼ÐµÐ½Ñ ÑÑнкÑии как именованнÑй, а заÑем пÑоÑÑо пиÑиÑе ÑÑо Ð¸Ð¼Ñ Ð² Ñеле ÑÑнкÑии. ÐÑли Ð¸Ð¼Ñ Ð°ÑгÑменÑа ÑÐ¾Ð²Ð¿Ð°Ð´Ð°ÐµÑ Ñ Ð¸Ð¼ÐµÐ½ÐµÐ¼ какого-либо ÑÑолбÑа в ÑекÑÑей SQL-команде внÑÑÑи ÑÑнкÑии, Ð¸Ð¼Ñ ÑÑолбÑа бÑÐ´ÐµÑ Ð¸Ð¼ÐµÑÑ Ð¿ÑиоÑиÑеÑ. ЧÑÐ¾Ð±Ñ Ð²ÑÑ Ð¶Ðµ пеÑекÑÑÑÑ Ð¸Ð¼Ñ ÑÑолбÑа, дополниÑе Ð¸Ð¼Ñ Ð°ÑгÑменÑа именем Ñамой ÑÑнкÑии, Ñо еÑÑÑ Ð·Ð°Ð¿Ð¸ÑиÑе его в виде . (ÐÑли и ÑÑо Ð¸Ð¼Ñ Ð±ÑÐ´ÐµÑ ÐºÐ¾Ð½ÑликÑоваÑÑ Ñ Ð¿Ð¾Ð»Ð½Ñм именем ÑÑолбÑа, Ñнова вÑигÑÐ°ÐµÑ Ð¸Ð¼Ñ ÑÑолбÑа. ÐеоднознаÑноÑÑи в ÑÑом ÑлÑÑае Ð²Ñ Ð¼Ð¾Ð¶ÐµÑе избежаÑÑ, вÑбÑав дÑÑгой пÑевдоним Ð´Ð»Ñ ÑаблиÑÑ Ð² SQL-команде.)имÑ_ÑÑнкÑии.имÑ_аÑгÑменÑа
СÑаÑÑй подÑ
од Ñ Ð½ÑмеÑаÑией позволÑÐµÑ Ð¾Ð±ÑаÑаÑÑÑÑ Ðº аÑгÑменÑам, пÑименÑÑ Ð·Ð°Ð¿Ð¸ÑÑ $: n$1 обознаÑÐ°ÐµÑ Ð¿ÐµÑвÑй аÑгÑменÑ, $2 â вÑоÑой и Ñ. д. ÐÑо бÑÐ´ÐµÑ ÑабоÑаÑÑ Ð¸ в Ñом ÑлÑÑае, еÑли Ð´Ð°Ð½Ð½Ð¾Ð¼Ñ Ð°ÑгÑменÑÑ Ð½Ð°Ð·Ð½Ð°Ñено имÑ.
ÐÑли аÑгÑÐ¼ÐµÐ½Ñ Ð¸Ð¼ÐµÐµÑ ÑоÑÑавной Ñип, Ñо Ð´Ð»Ñ Ð¾Ð±ÑаÑÐµÐ½Ð¸Ñ Ðº его аÑÑибÑÑам можно иÑполÑзоваÑÑ Ð·Ð°Ð¿Ð¸ÑÑ Ñ ÑоÑкой, напÑимеÑ: или аÑгÑменÑ.поле$1.. РопÑÑÑ Ð¶Ðµ, пÑи ÑÑом Ð¼Ð¾Ð¶ÐµÑ Ð¿Ð¾ÑÑебоваÑÑÑÑ Ð´Ð¾Ð¿Ð¾Ð»Ð½Ð¸ÑÑ Ð¸Ð¼Ñ Ð°ÑгÑменÑа именем ÑÑнкÑии, ÑÑÐ¾Ð±Ñ ÑделаÑÑ Ð¸Ð¼Ñ Ð°ÑгÑменÑа однознаÑнÑм.поле
ÐÑгÑменÑÑ SQL-ÑÑнкÑии могÑÑ Ð¸ÑполÑзоваÑÑÑÑ ÑолÑко как знаÑÐµÐ½Ð¸Ñ Ð´Ð°Ð½Ð½ÑÑ , но не как иденÑиÑикаÑоÑÑ. ÐапÑимеÑ, ÑÑо пÑиемлемо:
INSERT INTO mytable VALUES ($1);
а ÑÑо не бÑÐ´ÐµÑ ÑабоÑаÑÑ:
INSERT INTO $1 VALUES (42);
ÐÑимеÑание
ÐозможноÑÑÑ Ð¾Ð±ÑаÑаÑÑÑÑ Ðº аÑгÑменÑам SQL-ÑÑнкÑий по именам поÑвилаÑÑ Ð² PostgreSQL 9.2. Ð ÑÑнкÑиÑÑ
, коÑоÑÑе Ð´Ð¾Ð»Ð¶Ð½Ñ ÑабоÑаÑÑ Ñо ÑÑаÑÑми ÑеÑвеÑами, необÑ
одимо пÑименÑÑÑ Ð·Ð°Ð¿Ð¸ÑÑ $.n
36.5.2. ФÑнкÑии SQL Ñ Ð±Ð°Ð·Ð¾Ð²Ñми Ñипами #
ÐÑоÑÑейÑÐ°Ñ Ð²Ð¾Ð·Ð¼Ð¾Ð¶Ð½Ð°Ñ ÑÑнкÑÐ¸Ñ SQL не Ð¸Ð¼ÐµÐµÑ Ð°ÑгÑменÑов и пÑоÑÑо возвÑаÑÐ°ÐµÑ Ð±Ð°Ð·Ð¾Ð²Ñй Ñип, напÑÐ¸Ð¼ÐµÑ integer:
CREATE FUNCTION one() RETURNS integer AS $$
SELECT 1 AS result;
$$ LANGUAGE SQL;
-- ÐлÑÑеÑнаÑÐ¸Ð²Ð½Ð°Ñ Ð·Ð°Ð¿Ð¸ÑÑ ÑÑÑоковой конÑÑанÑÑ:
CREATE FUNCTION one() RETURNS integer AS '
SELECT 1 AS result;
' LANGUAGE SQL;
SELECT one();
one
-----
1
ÐамеÑÑÑе, ÑÑо Ð¼Ñ Ð¾Ð¿Ñеделили пÑевдоним ÑÑолбÑа в Ñеле ÑÑнкÑии Ð´Ð»Ñ ÐµÑ ÑезÑлÑÑаÑа (дали ÐµÐ¼Ñ Ð¸Ð¼Ñ result), но ÑÑÐ¾Ñ Ð¿Ñевдоним не виден ÑнаÑÑжи ÑÑнкÑии. ÐÑледÑÑвие ÑÑого, ÑÑÐ¾Ð»Ð±ÐµÑ ÑезÑлÑÑаÑа полÑÑил Ð¸Ð¼Ñ one, а не result.
ÐÑакÑиÑеÑки Ñак же легко опÑеделÑÑÑÑÑ ÑÑнкÑии SQL, коÑоÑÑе пÑинимаÑÑ Ð² аÑгÑменÑÐ°Ñ Ð±Ð°Ð·Ð¾Ð²Ñе ÑипÑ:
CREATE FUNCTION add_em(x integer, y integer) RETURNS integer AS $$
SELECT x + y;
$$ LANGUAGE SQL;
SELECT add_em(1, 2) AS answer;
answer
--------
3
ÐÑ Ñакже можем оÑказаÑÑÑÑ Ð¾Ñ Ð¸Ð¼Ñн аÑгÑменÑов и обÑаÑаÑÑÑÑ Ðº ним по номеÑам:
CREATE FUNCTION add_em(integer, integer) RETURNS integer AS $$
SELECT $1 + $2;
$$ LANGUAGE SQL;
SELECT add_em(1, 2) AS answer;
answer
--------
3
ÐÐ¾Ñ Ð±Ð¾Ð»ÐµÐµ Ð¿Ð¾Ð»ÐµÐ·Ð½Ð°Ñ ÑÑнкÑиÑ, коÑоÑÑÑ Ð¼Ð¾Ð¶Ð½Ð¾ иÑполÑзоваÑÑ, ÑÑÐ¾Ð±Ñ Ð´ÐµÐ±ÐµÑоваÑÑ Ð±Ð°Ð½ÐºÐ¾Ð²Ñкий ÑÑÑÑ:
CREATE FUNCTION tf1 (accountno integer, debit numeric) RETURNS numeric AS $$
UPDATE bank
SET balance = balance - debit
WHERE accountno = tf1.accountno;
SELECT 1;
$$ LANGUAGE SQL;ÐолÑзоваÑÐµÐ»Ñ Ð¼Ð¾Ð¶ÐµÑ Ð²ÑполниÑÑ ÑÑÑ ÑÑнкÑиÑ, ÑÑÐ¾Ð±Ñ Ð´ÐµÐ±ÐµÑоваÑÑ ÑÑÑÑ 17 на 100 доллаÑов, Ñак:
SELECT tf1(17, 100.0);
Ð ÑÑом пÑимеÑе Ð¼Ñ Ð²ÑбÑали Ð¸Ð¼Ñ accountno Ð´Ð»Ñ Ð¿ÐµÑвого аÑгÑменÑа, но ÑÑо же Ð¸Ð¼Ñ Ð¸Ð¼ÐµÐµÑ ÑÑÐ¾Ð»Ð±ÐµÑ Ð² ÑаблиÑе bank. Ркоманде UPDATE Ð¸Ð¼Ñ accountno оÑноÑиÑÑÑ Ðº ÑÑолбÑÑ bank.accountno, Ñак Ð´Ð»Ñ Ð¾Ð±ÑаÑÐµÐ½Ð¸Ñ Ðº аÑгÑменÑÑ Ð½Ñжно запиÑаÑÑ tf1.accountno. ÐонеÑно, Ð¼Ñ Ð¼Ð¾Ð³Ð»Ð¸ Ð±Ñ Ð¸Ð·Ð±ÐµÐ¶Ð°ÑÑ ÑÑого, вÑбÑав дÑÑгое Ð¸Ð¼Ñ Ð´Ð»Ñ Ð°ÑгÑменÑа.
Ðа пÑакÑике обÑÑно желаÑелÑно полÑÑаÑÑ Ð¾Ñ ÑÑнкÑии более полезнÑй ÑезÑлÑÑаÑ, Ñем конÑÑанÑÑ 1, поÑÑÐ¾Ð¼Ñ Ð±Ð¾Ð»ÐµÐµ ÑеалиÑÑиÑно Ñакое опÑеделение:
CREATE FUNCTION tf1 (accountno integer, debit numeric) RETURNS numeric AS $$
UPDATE bank
SET balance = balance - debit
WHERE accountno = tf1.accountno;
SELECT balance FROM bank WHERE accountno = tf1.accountno;
$$ LANGUAGE SQL; ÐÑа ÑÑнкÑÐ¸Ñ Ð¸Ð·Ð¼ÐµÐ½ÑÐµÑ Ð±Ð°Ð»Ð°Ð½Ñ Ð¸ возвÑаÑÐ°ÐµÑ Ð¿Ð¾Ð»ÑÑенное знаÑение. То же Ñамое можно ÑделаÑÑ Ð² одной команде, пÑименив RETURNING:
CREATE FUNCTION tf1 (accountno integer, debit numeric) RETURNS numeric AS $$
UPDATE bank
SET balance = balance - debit
WHERE accountno = tf1.accountno
RETURNING balance;
$$ LANGUAGE SQL;ÐÑли поÑледнÑÑ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð° SELECT или RETURNING в SQL-ÑÑнкÑии возвÑаÑÐ°ÐµÑ Ð½Ðµ в ÑоÑноÑÑи обÑÑвленнÑй Ñип ÑезÑлÑÑаÑа, PostgreSQL авÑомаÑиÑеÑки пÑиведÑÑ Ð²Ð¾Ð·Ð²ÑаÑаемое знаÑение к нÑÐ¶Ð½Ð¾Ð¼Ñ ÑипÑ, еÑли ÑÑо возможно Ñ Ð¿Ñименением пÑÐ¸Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¿ÑиÑÐ²Ð°Ð¸Ð²Ð°Ð½Ð¸Ñ Ð¸Ð»Ð¸ неÑвнÑм обÑазом. РпÑоÑивном ÑлÑÑае Ð²Ñ Ð´Ð¾Ð»Ð¶Ð½Ñ Ð¿ÑимениÑÑ Ñвное пÑиведение. ÐапÑимеÑ, пÑедположим, ÑÑо Ð¼Ñ Ð·Ð°Ñ
оÑели измениÑÑ Ð²Ð¾Ð·Ð²ÑаÑаемÑй Ñип в пÑедÑдÑÑей ÑÑнкÑии add_em на float8. ÐÑо можно ÑделаÑÑ Ñак:
CREATE FUNCTION add_em(integer, integer) RETURNS float8 AS $$
SELECT $1 + $2;
$$ LANGUAGE SQL; СÑмма Ñипа integer Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð½ÐµÑвно пÑиведена к ÑÐ¸Ð¿Ñ float8, поÑÑÐ¾Ð¼Ñ Ð´Ð¾ÑÑаÑоÑно ÑмениÑÑ ÑолÑко Ñип ÑезÑлÑÑаÑа. (ÐодÑобнее о пÑиведениÑÑ
говоÑиÑÑÑ Ð² Ðлаве 10 и опиÑании CREATE CAST.)
36.5.3. ФÑнкÑии SQL Ñ ÑоÑÑавнÑми Ñипами #
Ð ÑÑнкÑиÑÑ
Ñ Ð°ÑгÑменÑами ÑоÑÑавнÑÑ
Ñипов Ð¼Ñ Ð´Ð¾Ð»Ð¶Ð½Ñ ÑказÑваÑÑ Ð½Ðµ ÑолÑко, какой аÑгÑменÑ, но и какой аÑÑибÑÑ (поле) ÑÑого аÑгÑменÑа нам нÑжен. ÐапÑимеÑ, пÑедположим, ÑÑо emp â ÑаблиÑа, ÑодеÑжаÑÐ°Ñ Ð´Ð°Ð½Ð½Ñе ÑабоÑников, и ÑÑо же Ð¸Ð¼Ñ ÑоÑÑавного Ñипа, пÑедÑÑавлÑÑÑего каждÑÑ ÑÑÑÐ¾ÐºÑ ÑаблиÑÑ. СледÑÑÑÐ°Ñ ÑÑнкÑÐ¸Ñ double_salary вÑÑиÑлÑеÑ, каким бÑло Ð±Ñ ÑÑÑ-либо жалование в ÑлÑÑае ÑвелиÑÐµÐ½Ð¸Ñ Ð²Ð´Ð²Ð¾Ðµ:
CREATE TABLE emp (
name text,
salary numeric,
age integer,
cubicle point
);
INSERT INTO emp VALUES ('Bill', 4200, 45, '(2,1)');
CREATE FUNCTION double_salary(emp) RETURNS numeric AS $$
SELECT $1.salary * 2 AS salary;
$$ LANGUAGE SQL;
SELECT name, double_salary(emp.*) AS dream
FROM emp
WHERE emp.cubicle ~= point '(2,1)';
name | dream
------+-------
Bill | 8400
ÐбÑаÑиÑе внимание на запиÑÑ $1.salary позволÑÑÑÑÑ Ð²ÑбÑаÑÑ Ð¾Ð´Ð½Ð¾ поле из знаÑÐµÐ½Ð¸Ñ ÑÑÑоки аÑгÑменÑа. Также замеÑÑÑе, ÑÑо в вÑзÑваÑÑей команде SELECT Ñказание имÑ_ÑаблиÑÑ.* вÑбиÑÐ°ÐµÑ Ð²ÑÑ ÑекÑÑÑÑ ÑÑÑÐ¾ÐºÑ ÑаблиÑÑ ÐºÐ°Ðº ÑоÑÑавное знаÑение. Ðа ÑÑÑÐ¾ÐºÑ ÑаблиÑÑ Ð¼Ð¾Ð¶Ð½Ð¾ ÑоÑлаÑÑÑÑ Ð¸ пÑоÑÑо по имени ÑаблиÑÑ, напÑÐ¸Ð¼ÐµÑ Ñак:
SELECT name, double_salary(emp) AS dream
FROM emp
WHERE emp.cubicle ~= point '(2,1)';
Ðднако ÑÑо иÑполÑзование ÑÑиÑаеÑÑÑ ÑÑÑаÑевÑим, Ñак как пÑовоÑиÑÑÐµÑ Ð¿ÑÑаниÑÑ. (ÐодÑобнее ÑÑи две запиÑи ÑоÑÑавнÑÑ Ð·Ð½Ð°Ñений ÑÑÑоки ÑаблиÑÑ Ð¾Ð¿Ð¸ÑÐ°Ð½Ñ Ð² ÐодÑазделе 8.16.5.)
Ðногда бÑÐ²Ð°ÐµÑ Ñдобно обÑазоваÑÑ ÑоÑÑавное знаÑение аÑгÑменÑа на леÑÑ. ÐÑо позволÑÐµÑ ÑделаÑÑ ÐºÐ¾Ð½ÑÑÑÑкÑÐ¸Ñ ROW. ÐапÑимеÑ, Ñак можно измениÑÑ Ð´Ð°Ð½Ð½Ñе, пеÑедаваемÑе ÑÑнкÑии:
SELECT name, double_salary(ROW(name, salary*1.1, age, cubicle)) AS dream
FROM emp;
Также возможно ÑоздаÑÑ ÑÑнкÑиÑ, возвÑаÑаÑÑÑÑ ÑоÑÑавной Ñип. ÐапÑимеÑ, ÑÑа ÑÑнкÑÐ¸Ñ Ð²Ð¾Ð·Ð²ÑаÑÐ°ÐµÑ Ð¾Ð´Ð½Ñ ÑÑÑÐ¾ÐºÑ emp:
CREATE FUNCTION new_emp() RETURNS emp AS $$
SELECT text 'None' AS name,
1000.0 AS salary,
25 AS age,
point '(2,2)' AS cubicle;
$$ LANGUAGE SQL;Ð ÑÑом пÑимеÑе Ð¼Ñ Ð·Ð°Ð´Ð°Ð»Ð¸ Ð´Ð»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð³Ð¾ аÑÑибÑÑа поÑÑоÑнное знаÑение, но вмеÑÑо ÑÑÐ¸Ñ ÐºÐ¾Ð½ÑÑÐ°Ð½Ñ Ð¼Ð¾Ð¶Ð½Ð¾ подÑÑавиÑÑ Ð»ÑбÑе вÑÑиÑлениÑ.
УÑÑиÑе два важнÑÑ ÑÑÐµÐ±Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¾ÑноÑиÑелÑно опÑÐµÐ´ÐµÐ»ÐµÐ½Ð¸Ñ ÑÑнкÑии:
ÐоÑÑдок в ÑпиÑке вÑбоÑки внÑÑÑеннего запÑоÑа должен в ÑоÑноÑÑи ÑовпадаÑÑ Ñ Ð¿Ð¾ÑÑдком ÑÐ»ÐµÐ´Ð¾Ð²Ð°Ð½Ð¸Ñ ÑÑолбÑов в ÑоÑÑавном Ñипе. (Ðмена ÑÑолбÑов, как показÑÐ²Ð°ÐµÑ Ð¿ÑÐ¸Ð¼ÐµÑ Ð²ÑÑе, Ð´Ð»Ñ ÑиÑÑÐµÐ¼Ñ Ð·Ð½Ð°ÑÐµÐ½Ð¸Ñ Ð½Ðµ имеÑÑ.)
ÐÐµÐ¾Ð±Ñ Ð¾Ð´Ð¸Ð¼Ð¾ ÑделаÑÑ Ñак, ÑÑÐ¾Ð±Ñ ÐºÐ°Ð¶Ð´Ð¾Ðµ вÑÑажение могло пÑиводиÑÑÑÑ Ðº ÑÐ¸Ð¿Ñ ÑооÑвеÑÑÑвÑÑÑего ÑÑолбÑа ÑоÑÑавного Ñипа. РпÑоÑивном ÑлÑÑае Ð²Ñ Ð¿Ð¾Ð»ÑÑиÑе Ñакие оÑибки:
ERROR: return type mismatch in function declared to return emp DETAIL: Final statement returns text instead of point at column 4.(ÐШÐÐÐÐ: неÑовпадение Ñипа возвÑаÑа в ÑÑнкÑии (в обÑÑвлении Ñказан Ñип emp); ÐÐÐÐ ÐÐÐÐСТÐ: ÐоÑледний опеÑаÑÐ¾Ñ Ð²Ð¾Ð·Ð²ÑаÑÐ°ÐµÑ text вмеÑÑо point Ð´Ð»Ñ ÑÑолбÑа 4.) Ðак и в ÑлÑÑае Ñ Ð±Ð°Ð·Ð¾Ð²Ñми Ñипами, никакие ÑвнÑе пÑÐ¸Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ð°Ð²ÑомаÑиÑеÑки не добавлÑÑÑÑÑ, Ð²Ð¾Ð·Ð¼Ð¾Ð¶Ð½Ñ ÑолÑко пÑÐ¸Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¿ÑиÑÐ²Ð°Ð¸Ð²Ð°Ð½Ð¸Ñ Ð¸Ð»Ð¸ неÑвнÑе.
Ð¢Ñ Ð¶Ðµ ÑÑнкÑÐ¸Ñ Ð¼Ð¾Ð¶Ð½Ð¾ опÑеделиÑÑ Ð´ÑÑгим ÑпоÑобом:
CREATE FUNCTION new_emp() RETURNS emp AS $$
SELECT ROW('None', 1000.0, 25, '(2,2)')::emp;
$$ LANGUAGE SQL; ÐдеÑÑ Ð¼Ñ Ð·Ð°Ð¿Ð¸Ñали SELECT, коÑоÑÑй возвÑаÑÐ°ÐµÑ Ð¾Ð´Ð¸Ð½ ÑÑÐ¾Ð»Ð±ÐµÑ Ð½Ñжного ÑоÑÑавного Ñипа. Рданной ÑиÑÑаÑии ÑÑÐ¾Ñ Ð²Ð°ÑÐ¸Ð°Ð½Ñ Ð½Ð° Ñамом деле не лÑÑÑе, но в некоÑоÑÑÑ
ÑлÑÑаÑÑ
он Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ñдобной алÑÑеÑнаÑивой â напÑимеÑ, еÑли нам нÑжно вÑÑиÑлиÑÑ ÑезÑлÑÑаÑ, вÑзÑÐ²Ð°Ñ Ð´ÑÑгÑÑ ÑÑнкÑиÑ, коÑоÑÐ°Ñ Ð²Ð¾Ð·Ð²ÑаÑÐ°ÐµÑ Ð½Ñжное ÑоÑÑавное знаÑение. ÐÑÐ¾Ñ Ð²Ð°ÑÐ¸Ð°Ð½Ñ Ð¿Ð¾Ð»ÐµÐ·ÐµÐ½ и в ÑлÑÑае, когда Ð¼Ñ Ñ
оÑим напиÑаÑÑ ÑÑнкÑиÑ, коÑоÑÐ°Ñ Ð²Ð¾Ð·Ð²ÑаÑÐ°ÐµÑ Ð½Ðµ обÑÑнÑй ÑоÑÑавной Ñип, а домен, опÑеделÑннÑй повеÑÑ
ÑоÑÑавного Ñипа; Ñогда она в лÑбом ÑлÑÑае должна опÑеделÑÑÑÑÑ ÐºÐ°Ðº возвÑаÑаÑÑÐ°Ñ ÐµÐ´Ð¸Ð½ÑÑвеннÑй ÑÑолбеÑ, Ñак как никакого ÑпоÑоба оÑÑÑеÑÑвиÑÑ Ð½Ñжное пÑиведение Ð´Ð»Ñ Ð²Ñей ÑÑÑоки ÑезÑлÑÑаÑа неÑ.
ÐÑ Ð¼Ð¾Ð¶ÐµÐ¼ вÑзÑваÑÑ ÑÑÑ ÑÑнкÑÐ¸Ñ Ð½Ð°Ð¿ÑÑмÑÑ, либо Ñказав ÐµÑ Ð² вÑÑажении знаÑениÑ:
SELECT new_emp();
new_emp
--------------------------
(None,1000.0,25,"(2,2)")
либо обÑаÑивÑиÑÑ Ðº ней, как к ÑаблиÑной ÑÑнкÑии:
SELECT * FROM new_emp(); name | salary | age | cubicle ------+--------+-----+--------- None | 1000.0 | 25 | (2,2)
ÐÑоÑой ÑпоÑоб более подÑобно опиÑан в ÐодÑазделе 36.5.8.
Ðогда иÑполÑзÑеÑÑÑ ÑÑнкÑиÑ, возвÑаÑаÑÑÐ°Ñ ÑоÑÑавной Ñип, Ð¼Ð¾Ð¶ÐµÑ Ð²Ð¾Ð·Ð½Ð¸ÐºÐ½ÑÑÑ Ð¶ÐµÐ»Ð°Ð½Ð¸Ðµ полÑÑиÑÑ Ð¸Ð· ÐµÑ ÑезÑлÑÑаÑа ÑолÑко одно поле (аÑÑибÑÑ). ÐÑо можно ÑделаÑÑ, пÑименÑÑ ÑакÑÑ Ð·Ð°Ð¿Ð¸ÑÑ:
SELECT (new_emp()).name; name ------ None
ÐополниÑелÑнÑе Ñкобки Ð½ÐµÐ¾Ð±Ñ Ð¾Ð´Ð¸Ð¼Ñ Ð²Ð¾ избежание неоднознаÑноÑÑи пÑи ÑазбоÑе запÑоÑа. ÐÑли Ð²Ñ Ð¿Ð¾Ð¿ÑÑаеÑеÑÑ Ð²ÑполниÑÑ Ð·Ð°Ð¿ÑÐ¾Ñ Ð±ÐµÐ· Ð½Ð¸Ñ , Ð²Ñ Ð¿Ð¾Ð»ÑÑиÑе оÑибкÑ:
SELECT new_emp().name;
ERROR: syntax error at or near "."
LINE 1: SELECT new_emp().name;
^
(ÐШÐÐÐÐ: ÑинÑакÑиÑеÑÐºÐ°Ñ Ð¾Ñибка (пÑимеÑное положение: "."))
ФÑнкÑионалÑнÑÑ Ð·Ð°Ð¿Ð¸ÑÑ Ñакже можно иÑполÑзоваÑÑ Ð¸ Ð´Ð»Ñ Ð¸Ð·Ð²Ð»ÐµÑÐµÐ½Ð¸Ñ Ð°ÑÑибÑÑов:
SELECT name(new_emp()); name ------ None
Ðак ÑаÑÑказÑвалоÑÑ Ð² ÐодÑазделе 8.16.5, запиÑÑ Ñ Ñказанием Ð¿Ð¾Ð»Ñ Ð¸ ÑÑнкÑионалÑÐ½Ð°Ñ Ð·Ð°Ð¿Ð¸ÑÑ ÑвлÑÑÑÑÑ ÑавнознаÑнÑми.
ÐÑÑ Ð¾Ð´Ð¸Ð½ ваÑÐ¸Ð°Ð½Ñ Ð¸ÑполÑÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ ÑÑнкÑии, возвÑаÑаÑÑей ÑоÑÑавной Ñип, заклÑÑаеÑÑÑ Ð² пеÑедаÑе ÐµÑ ÑезÑлÑÑаÑа дÑÑгой ÑÑнкÑии, коÑоÑÐ°Ñ Ð¿ÑÐ¸Ð½Ð¸Ð¼Ð°ÐµÑ ÑÑÐ¾Ñ Ñип ÑÑÑоки на Ð²Ñ Ð¾Ð´:
CREATE FUNCTION getname(emp) RETURNS text AS $$
SELECT $1.name;
$$ LANGUAGE SQL;
SELECT getname(new_emp());
getname
---------
None
(1 row)
36.5.4. ФÑнкÑии SQL Ñ Ð²ÑÑ Ð¾Ð´Ð½Ñми паÑамеÑÑами #
ÐлÑÑеÑнаÑивнÑй ÑпоÑоб опиÑаÑÑ ÑезÑлÑÑаÑÑ ÑÑнкÑии â опÑеделиÑÑ ÐµÑ Ñ Ð²ÑÑ Ð¾Ð´Ð½Ñми паÑамеÑÑами, как в ÑÑом пÑимеÑе:
CREATE FUNCTION add_em (IN x int, IN y int, OUT sum int)
AS 'SELECT x + y'
LANGUAGE SQL;
SELECT add_em(3,7);
add_em
--------
10
(1 row)
ÐÑо по ÑÑÑи не оÑлиÑаеÑÑÑ Ð¾Ñ Ð²ÐµÑÑии add_em, показанной в ÐодÑазделе 36.5.2. ÐейÑÑвиÑелÑÐ½Ð°Ñ ÑенноÑÑÑ Ð²ÑÑ
однÑÑ
паÑамеÑÑов в Ñом, ÑÑо они позволÑÑÑ ÑдобнÑм ÑпоÑобом опÑеделиÑÑ ÑÑнкÑии, возвÑаÑаÑÑие неÑколÑко ÑÑолбÑов. ÐапÑимеÑ:
CREATE FUNCTION sum_n_product (x int, y int, OUT sum int, OUT product int) AS 'SELECT x + y, x * y' LANGUAGE SQL; SELECT * FROM sum_n_product(11,42); sum | product -----+--------- 53 | 462 (1 row)
ФакÑиÑеÑки здеÑÑ Ð¼Ñ Ð¾Ð¿Ñеделили анонимнÑй ÑоÑÑавной Ñип Ð´Ð»Ñ ÑезÑлÑÑаÑа ÑÑнкÑии. ÐоказаннÑй вÑÑе пÑÐ¸Ð¼ÐµÑ Ð´Ð°ÑÑ ÑÐ¾Ñ Ð¶Ðµ конеÑнÑй ÑезÑлÑÑаÑ, ÑÑо и командÑ:
CREATE TYPE sum_prod AS (sum int, product int); CREATE FUNCTION sum_n_product (int, int) RETURNS sum_prod AS 'SELECT $1 + $2, $1 * $2' LANGUAGE SQL;
Ðо пÑедÑдÑÑий ваÑÐ¸Ð°Ð½Ñ Ð·Ð°ÑаÑÑÑÑ Ñдобнее, Ñак как он не ÑÑебÑÐµÑ Ð¾ÑделÑно занимаÑÑÑÑ Ð¾Ð¿Ñеделением ÑоÑÑавного Ñипа. ÐамеÑÑÑе, ÑÑо имена, назнаÑаемÑе вÑÑ Ð¾Ð´Ð½Ñм паÑамеÑÑам, не пÑоÑÑо декоÑаÑивнÑе, а опÑеделÑÑÑ Ð¸Ð¼ÐµÐ½Ð° ÑÑолбÑов анонимного ÑоÑÑавного Ñипа. (ÐÑли Ð²Ñ Ð¾Ð¿ÑÑÑиÑе Ð¸Ð¼Ñ Ð²ÑÑ Ð¾Ð´Ð½Ð¾Ð³Ð¾ паÑамеÑÑа, ÑиÑÑема вÑбеÑÐµÑ Ð¸Ð¼Ñ Ñама.)
ÐамеÑÑÑе, ÑÑо вÑÑ Ð¾Ð´Ð½Ñе паÑамеÑÑÑ Ð½Ðµ вклÑÑаÑÑÑÑ Ð² ÑпиÑок аÑгÑменÑов пÑи вÑзове Ñакой ÑÑнкÑии из SQL. ÐÑо обÑÑÑнÑеÑÑÑ Ñем, ÑÑо PostgreSQL опÑеделÑÐµÑ ÑигнаÑÑÑÑ Ð²Ñзова ÑÑнкÑии, ÑаÑÑмаÑÑÐ¸Ð²Ð°Ñ ÑолÑко Ð²Ñ Ð¾Ð´Ð½Ñе паÑамеÑÑÑ. ÐÑо Ñакже знаÑиÑ, ÑÑо пÑи ÑÐ°ÐºÐ¸Ñ Ð¾Ð¿ÐµÑаÑиÑÑ , как Ñдаление ÑÑнкÑии, в ÑÑÑÐ»ÐºÐ°Ñ Ð½Ð° ÑÑнкÑÐ¸Ñ ÑÑиÑÑваÑÑÑÑ ÑолÑко ÑÐ¸Ð¿Ñ Ð²Ñ Ð¾Ð´Ð½ÑÑ Ð¿Ð°ÑамеÑÑов. Таким обÑазом, ÑдалиÑÑ ÑÑÑ ÐºÐ¾Ð½ÐºÑеÑнÑÑ ÑÑнкÑÐ¸Ñ Ð¼Ð¾Ð¶Ð½Ð¾ лÑбой из ÑÑÐ¸Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´:
DROP FUNCTION sum_n_product (x int, y int, OUT sum int, OUT product int); DROP FUNCTION sum_n_product (int, int);
ÐаÑамеÑÑÑ ÑÑнкÑии могÑÑ Ð±ÑÑÑ Ð¾Ð±ÑÑÐ²Ð»ÐµÐ½Ñ ÐºÐ°Ðº IN (по ÑмолÑаниÑ), OUT, INOUT или VARIADIC. ÐаÑамеÑÑ INOUT дейÑÑвÑÐµÑ ÐºÐ°Ðº вÑ
одной (ÑвлÑеÑÑÑ ÑаÑÑÑÑ ÑпиÑка аÑгÑменÑов пÑи вÑзове) и как вÑÑ
одной (ÑаÑÑÑ Ñипа запиÑи ÑезÑлÑÑаÑа). ÐаÑамеÑÑÑ VARIADIC ÑвлÑÑÑÑÑ Ð²Ñ
однÑми, но обÑабаÑÑваеÑÑÑ ÑпеÑиалÑнÑм обÑазом, как опиÑано далее.
36.5.5. ÐÑоÑедÑÑÑ SQL Ñ Ð²ÑÑ Ð¾Ð´Ð½Ñми паÑамеÑÑами #
ÐÑоÑедÑÑÑ Ñакже поддеÑживаÑÑ Ð²ÑÑ
однÑе паÑамеÑÑÑ, но неÑколÑко инаÑе, Ñем ÑÑнкÑии. РкомандаÑ
CALL вÑÑ
однÑе паÑамеÑÑÑ Ð´Ð¾Ð»Ð¶Ð½Ñ Ð±ÑÑÑ Ð²ÐºÐ»ÑÑÐµÐ½Ñ Ð² ÑпиÑок аÑгÑменÑов. ÐапÑимеÑ, опиÑаннÑÑ Ñанее опеÑаÑÐ¸Ñ ÑпиÑÐ°Ð½Ð¸Ñ ÑÑедÑÑв Ñ Ð±Ð°Ð½ÐºÐ¾Ð²Ñкого ÑÑеÑа можно запиÑаÑÑ ÑледÑÑÑим обÑазом:
CREATE PROCEDURE tp1 (accountno integer, debit numeric, OUT new_balance numeric) AS $$
UPDATE bank
SET balance = balance - debit
WHERE accountno = tp1.accountno
RETURNING balance;
$$ LANGUAGE SQL; ÐÐ»Ñ Ð²Ñзова ÑÑой пÑоÑедÑÑÑ Ð½ÐµÐ¾Ð±Ñ
одимо задаÑÑ Ð°ÑгÑменÑ, ÑооÑвеÑÑÑвÑÑÑий паÑамеÑÑÑ OUT. ÐбÑÑно пÑинÑÑо пиÑаÑÑ NULL:
CALL tp1(17, 100.0, NULL);
ÐÑли Ð²Ñ Ð¿Ð¸ÑеÑе ÑÑо-Ñо еÑÑ, Ñо ÑÑо должно бÑÑÑ Ð²ÑÑажение, неÑвно пÑиводимое к обÑÑÐ²Ð»ÐµÐ½Ð½Ð¾Ð¼Ñ ÑÐ¸Ð¿Ñ Ð¿Ð°ÑамеÑÑа, как и Ð´Ð»Ñ Ð²Ñ Ð¾Ð´Ð½ÑÑ Ð¿Ð°ÑамеÑÑов. Ðднако обÑаÑиÑе внимание, ÑÑо Ñакое вÑÑажение не вÑÑиÑлÑеÑÑÑ.
ÐÑзÑÐ²Ð°Ñ Ð¿ÑоÑедÑÑÑ Ð¸Ð· PL/pgSQL, вмеÑÑо NULL Ð²Ñ Ð´Ð¾Ð»Ð¶Ð½Ñ Ð½Ð°Ð¿Ð¸ÑаÑÑ Ð¿ÐµÑеменнÑÑ, коÑоÑÐ°Ñ Ð±ÑÐ´ÐµÑ Ð¿Ð¾Ð»ÑÑаÑÑ ÑезÑлÑÑÐ°Ñ Ð¿ÑоÑедÑÑÑ. Ðа подÑобноÑÑÑми обÑаÑиÑеÑÑ Ðº ÐодÑазделÑ 41.6.3.
36.5.6. ФÑнкÑии SQL Ñ Ð¿ÐµÑеменнÑм ÑиÑлом аÑгÑменÑов #
ФÑнкÑии SQL могÑÑ Ð±ÑÑÑ Ð¾Ð±ÑÑÐ²Ð»ÐµÐ½Ñ ÐºÐ°Ðº пÑинимаÑÑие пеÑеменное ÑиÑло аÑгÑменÑов, Ñ ÑÑловием, ÑÑо вÑе «необÑзаÑелÑнÑе» аÑгÑменÑÑ Ð¸Ð¼ÐµÑÑ Ð¾Ð´Ð¸Ð½ Ñип даннÑÑ
. ÐеобÑзаÑелÑнÑе аÑгÑменÑÑ Ð±ÑдÑÑ Ð¿ÐµÑÐµÐ´Ð°Ð½Ñ Ñакой ÑÑнкÑии в виде маÑÑива. ÐÐ»Ñ ÑÑого в обÑÑвлении ÑÑнкÑии поÑледний паÑамеÑÑ Ð¿Ð¾Ð¼ÐµÑаеÑÑÑ ÐºÐ°Ðº VARIADIC; пÑи ÑÑом он должен имеÑÑ Ñип маÑÑива. ÐапÑимеÑ:
CREATE FUNCTION mleast(VARIADIC arr numeric[]) RETURNS numeric AS $$
SELECT min($1[i]) FROM generate_subscripts($1, 1) g(i);
$$ LANGUAGE SQL;
SELECT mleast(10, -1, 5, 4.4);
mleast
--------
-1
(1 row)
Ðо ÑÑÑи, вÑе ÑакÑиÑеÑкие аÑгÑменÑÑ, наÑÐ¸Ð½Ð°Ñ Ñ Ð¿Ð¾Ð·Ð¸Ñии VARIADIC, ÑобиÑаÑÑÑÑ Ð² одномеÑнÑй маÑÑив, как еÑли Ð±Ñ Ð²Ñ Ð½Ð°Ð¿Ð¸Ñали
SELECT mleast(ARRAY[10, -1, 5, 4.4]); -- ÑÑо не бÑÐ´ÐµÑ ÑабоÑаÑÑ
Ðа Ñамом деле Ñак вÑзваÑÑ ÑÑÑ ÑÑнкÑÐ¸Ñ Ð½ÐµÐ»ÑзÑ, или, по кÑайней меÑе, ÑÑо не бÑÐ´ÐµÑ ÑооÑвеÑÑÑвоваÑÑ Ð¾Ð¿ÑÐµÐ´ÐµÐ»ÐµÐ½Ð¸Ñ ÑÑнкÑии. ÐаÑамеÑÑÑ VARIADIC ÑооÑвеÑÑÑвÑÑÑ Ð¾Ð´Ð½Ð¾ или неÑколÑко вÑ
ождений Ñипа его ÑлеменÑа, но не его ÑобÑÑвенного Ñипа.
Ðо иногда бÑÐ²Ð°ÐµÑ Ð¿Ð¾Ð»ÐµÐ·Ð½Ð¾ пеÑедаÑÑ ÑÑнкÑии Ñ Ð¿ÐµÑеменнÑми паÑамеÑÑами Ñже подгоÑовленнÑй маÑÑив; оÑобенно когда одна ÑÑнкÑÐ¸Ñ Ñ Ð¿ÐµÑеменнÑми паÑамеÑÑами Ñ
оÑÐµÑ Ð¿ÐµÑедаваÑÑ Ñвой маÑÑив паÑамеÑÑов дÑÑгой. Также ÑÑо более безопаÑнÑй ÑпоÑоб вÑзÑваÑÑ ÑакÑÑ ÑÑнкÑиÑ, ÑÑÑеÑÑвÑÑÑÑÑ Ð² ÑÑ
еме, где могÑÑ ÑоздаваÑÑ Ð¾Ð±ÑекÑÑ Ð½ÐµÐ´Ð¾Ð²ÐµÑеннÑе полÑзоваÑели; Ñм. Раздел 10.3. ÐÑо можно ÑделаÑÑ, добавив VARIADIC в вÑзов:
SELECT mleast(VARIADIC ARRAY[10, -1, 5, 4.4]);
ÐÑо пÑедоÑвÑаÑÐ°ÐµÑ ÑазвоÑаÑивание пеÑеменного множеÑÑва паÑамеÑÑов ÑÑнкÑии в базовÑй Ñип, ÑÑо позволÑÐµÑ ÑопоÑÑавиÑÑ Ñ Ð½Ð¸Ð¼ знаÑение Ñипа маÑÑива. VARIADIC можно добавиÑÑ ÑолÑко к поÑÐ»ÐµÐ´Ð½ÐµÐ¼Ñ ÑакÑиÑеÑÐºÐ¾Ð¼Ñ Ð°ÑгÑменÑÑ Ð²Ñзова ÑÑнкÑии.
Также Ñказание VARIADIC даÑÑ ÐµÐ´Ð¸Ð½ÑÑвеннÑÑ Ð²Ð¾Ð·Ð¼Ð¾Ð¶Ð½Ð¾ÑÑÑ Ð¿ÐµÑедаÑÑ Ð¿ÑÑÑой маÑÑив ÑÑнкÑии Ñ Ð¿ÐµÑеменнÑми паÑамеÑÑами, напÑимеÑ, Ñак:
SELECT mleast(VARIADIC ARRAY[]::numeric[]);
ÐÑоÑÑой вÑзов SELECT mleast() не бÑÐ´ÐµÑ ÑабоÑаÑÑ, Ñак как пеÑеменнÑм паÑамеÑÑам должен ÑооÑвеÑÑÑвоваÑÑ Ð¼Ð¸Ð½Ð¸Ð¼Ñм один ÑакÑиÑеÑкий аÑгÑменÑ. (Ðожно опÑеделиÑÑ Ð²ÑоÑÑÑ ÑÑнкÑÐ¸Ñ Ñ Ñаким же именем mleast, но без паÑамеÑÑов, еÑли Ð²Ñ Ñ
оÑиÑе вÑполнÑÑÑ Ñакие вÑзовÑ.)
ÐлеменÑÑ Ð¼Ð°ÑÑива, ÑоздаваемÑе из пеÑеменнÑÑ
паÑамеÑÑов, ÑÑиÑаÑÑÑÑ Ð½Ðµ имеÑÑими ÑобÑÑвеннÑÑ
имÑн. ÐÑо ознаÑаеÑ, ÑÑо пеÑедаÑÑ ÑÑнкÑии Ñ Ð¿ÐµÑеменнÑми паÑамеÑÑами именованнÑе аÑгÑменÑÑ Ð½ÐµÐ»ÑÐ·Ñ (Ñм. Раздел 4.3), еÑли ÑолÑко пÑи вÑзове не добавлено VARIADIC. ÐапÑимеÑ, ÑÑÐ¾Ñ Ð²Ð°ÑÐ¸Ð°Ð½Ñ Ð±ÑÐ´ÐµÑ ÑабоÑаÑÑ:
SELECT mleast(VARIADIC arr => ARRAY[10, -1, 5, 4.4]);
Ð ÑÑи ваÑианÑÑ Ð½ÐµÑ:
SELECT mleast(arr => 10); SELECT mleast(arr => ARRAY[10, -1, 5, 4.4]);
36.5.7. ФÑнкÑии SQL Ñо знаÑениÑми аÑгÑменÑов по ÑмолÑÐ°Ð½Ð¸Ñ #
ФÑнкÑии могÑÑ Ð±ÑÑÑ Ð¾Ð±ÑÑÐ²Ð»ÐµÐ½Ñ Ñо знаÑениÑми по ÑмолÑÐ°Ð½Ð¸Ñ Ð´Ð»Ñ Ð½ÐµÐºÐ¾ÑоÑÑÑ Ð¸Ð»Ð¸ вÑÐµÑ Ð²Ñ Ð¾Ð´Ð½ÑÑ Ð°ÑгÑменÑов. ÐнаÑÐµÐ½Ð¸Ñ Ð¿Ð¾ ÑмолÑÐ°Ð½Ð¸Ñ Ð¿Ð¾Ð´ÑÑавлÑÑÑÑÑ, когда ÑÑнкÑÐ¸Ñ Ð²ÑзÑваеÑÑÑ Ñ Ð½ÐµÐ´Ð¾ÑÑаÑоÑнÑм колиÑеÑÑвом ÑакÑиÑеÑÐºÐ¸Ñ Ð°ÑгÑменÑов. Так как аÑгÑменÑÑ Ð¼Ð¾Ð¶Ð½Ð¾ опÑÑкаÑÑ ÑолÑко Ñ ÐºÐ¾Ð½Ñа ÑпиÑка ÑакÑиÑеÑÐºÐ¸Ñ Ð°ÑгÑменÑов, вÑе паÑамеÑÑÑ Ð¿Ð¾Ñле паÑамеÑÑа Ñо знаÑением по ÑмолÑÐ°Ð½Ð¸Ñ Ñакже полÑÑÐ°Ñ Ð·Ð½Ð°ÑÐµÐ½Ð¸Ñ Ð¿Ð¾ ÑмолÑаниÑ. (ХоÑÑ Ð·Ð°Ð¿Ð¸ÑÑ Ñ Ð¸Ð¼ÐµÐ½Ð¾Ð²Ð°Ð½Ð½Ñми аÑгÑменÑами могла Ð±Ñ Ð¾ÑлабиÑÑ ÑÑо огÑаниÑение, оно вÑÑ Ð¶Ðµ оÑÑаÑÑÑÑ Ð² Ñиле, ÑÑÐ¾Ð±Ñ Ð¿Ð¾Ð·Ð¸ÑионнÑе ÑÑÑлки на аÑгÑменÑÑ Ð¾ÑÑавалиÑÑ Ð´ÐµÐ¹ÑÑвиÑелÑнÑми.) ÐезавиÑимо Ð¾Ñ Ñого, иÑполÑзÑеÑе Ð²Ñ ÑÑÑ Ð²Ð¾Ð·Ð¼Ð¾Ð¶Ð½Ð¾ÑÑÑ Ð¸Ð»Ð¸ неÑ, она ÑÑебÑÐµÑ Ð¾ÑÑоÑожноÑÑи пÑи вÑзове ÑÑнкÑий в Ð±Ð°Ð·Ð°Ñ Ð´Ð°Ð½Ð½ÑÑ , где одни полÑзоваÑели не довеÑÑÑÑ Ð´ÑÑгим; Ñм. Раздел 10.3.
ÐапÑимеÑ:
CREATE FUNCTION foo(a int, b int DEFAULT 2, c int DEFAULT 3)
RETURNS int
LANGUAGE SQL
AS $$
SELECT $1 + $2 + $3;
$$;
SELECT foo(10, 20, 30);
foo
-----
60
(1 row)
SELECT foo(10, 20);
foo
-----
33
(1 row)
SELECT foo(10);
foo
-----
15
(1 row)
SELECT foo(); -- не ÑабоÑÐ°ÐµÑ Ð¸Ð·-за оÑÑÑÑÑÑÐ²Ð¸Ñ Ð·Ð½Ð°ÑÐµÐ½Ð¸Ñ Ð¿Ð¾ ÑмолÑÐ°Ð½Ð¸Ñ Ð´Ð»Ñ Ð¿ÐµÑвого аÑгÑменÑа
ERROR: function foo() does not exist
(ÐШÐÐÐÐ: ÑÑнкÑÐ¸Ñ foo() не ÑÑÑеÑÑвÑеÑ) ÐмеÑÑо клÑÑевого Ñлова DEFAULT можно иÑполÑзоваÑÑ Ð·Ð½Ð°Ðº =.
36.5.8. ФÑнкÑии SQL, поÑождаÑÑие ÑаблиÑÑ #
ÐÑе ÑÑнкÑии SQL можно иÑполÑзоваÑÑ Ð² пÑедложении FROM запÑоÑов, но наиболее полезно ÑÑо Ð´Ð»Ñ ÑÑнкÑий, возвÑаÑаÑÑиÑ
ÑоÑÑавнÑе ÑипÑ. ÐÑли ÑÑнкÑÐ¸Ñ Ð¾Ð±ÑÑвлена как возвÑаÑаÑÑÐ°Ñ Ð±Ð°Ð·Ð¾Ð²Ñй Ñип, она возвÑаÑÐ°ÐµÑ ÑаблиÑÑ Ñ Ð¾Ð´Ð½Ð¸Ð¼ ÑÑолбÑом. ÐÑли же ÑÑнкÑÐ¸Ñ Ð¾Ð±ÑÑвлена как возвÑаÑаÑÑÐ°Ñ ÑоÑÑавной Ñип, она возвÑаÑÐ°ÐµÑ ÑаблиÑÑ Ñо ÑÑолбÑами Ð´Ð»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð³Ð¾ аÑÑибÑÑа ÑоÑÑавного Ñипа.
ÐапÑимеÑ:
CREATE TABLE foo (fooid int, foosubid int, fooname text);
INSERT INTO foo VALUES (1, 1, 'Joe');
INSERT INTO foo VALUES (1, 2, 'Ed');
INSERT INTO foo VALUES (2, 1, 'Mary');
CREATE FUNCTION getfoo(int) RETURNS foo AS $$
SELECT * FROM foo WHERE fooid = $1;
$$ LANGUAGE SQL;
SELECT *, upper(fooname) FROM getfoo(1) AS t1;
fooid | foosubid | fooname | upper
-------+----------+---------+-------
1 | 1 | Joe | JOE
(1 row)
Ðак показÑÐ²Ð°ÐµÑ ÑÑÐ¾Ñ Ð¿ÑимеÑ, Ð¼Ñ Ð¼Ð¾Ð¶ÐµÐ¼ ÑабоÑаÑÑ Ñо ÑÑолбÑами ÑезÑлÑÑаÑа ÑÑнкÑии Ñак же, как еÑли Ð±Ñ ÑÑо бÑли ÑÑолбÑÑ Ð¾Ð±ÑÑной ÑаблиÑÑ.
ÐамеÑÑÑе, ÑÑо Ð¼Ñ Ð¿Ð¾Ð»ÑÑаем из данной ÑÑнкÑии ÑолÑко Ð¾Ð´Ð½Ñ ÑÑÑокÑ. ÐÑо обÑÑÑнÑеÑÑÑ Ñем, ÑÑо Ð¼Ñ Ð½Ðµ иÑполÑзовали Ñказание SETOF. Ðно опиÑÑваеÑÑÑ Ð² ÑледÑÑÑем Ñазделе.
36.5.9. ФÑнкÑии SQL, возвÑаÑаÑÑие множеÑÑва #
Ðогда SQL-ÑÑнкÑÐ¸Ñ Ð¾Ð±ÑÑвлÑеÑÑÑ ÐºÐ°Ðº возвÑаÑаÑÑÐ°Ñ SETOF , конеÑнÑй запÑÐ¾Ñ ÑÑнкÑии вÑполнÑеÑÑÑ Ð´Ð¾ завеÑÑÐµÐ½Ð¸Ñ Ð¸ ÐºÐ°Ð¶Ð´Ð°Ñ ÑÑÑока вÑводиÑÑÑ ÐºÐ°Ðº ÑÐ»ÐµÐ¼ÐµÐ½Ñ ÑезÑлÑÑиÑÑÑÑего множеÑÑва.некий_Ñип
ÐÑо обÑÑно иÑполÑзÑеÑÑÑ, когда ÑÑнкÑÐ¸Ñ Ð²ÑзÑваеÑÑÑ Ð² пÑедложении FROM. Ð ÑÑом ÑлÑÑае ÐºÐ°Ð¶Ð´Ð°Ñ ÑÑÑока, возвÑаÑÐ°ÐµÐ¼Ð°Ñ ÑÑнкÑией, ÑÑановиÑÑÑ ÑÑÑокой ÑаблиÑÑ, поÑвлÑÑÑейÑÑ Ð² запÑоÑе. ÐапÑимеÑ, в пÑедположении, ÑÑо ÑаблиÑа foo Ð¸Ð¼ÐµÐµÑ Ñо же ÑодеÑжимое, ÑÑо и ÑанÑÑе, Ð¼Ñ Ð²ÑполнÑем:
CREATE FUNCTION getfoo(int) RETURNS SETOF foo AS $$
SELECT * FROM foo WHERE fooid = $1;
$$ LANGUAGE SQL;
SELECT * FROM getfoo(1) AS t1;Тогда в оÑÐ²ÐµÑ Ð¼Ñ Ð¿Ð¾Ð»ÑÑим:
fooid | foosubid | fooname
-------+----------+---------
1 | 1 | Joe
1 | 2 | Ed
(2 rows)
Также возможно вÑдаÑÑ Ð½ÐµÑколÑко ÑÑÑок Ñо ÑÑолбÑами, опÑеделÑемÑми вÑÑ Ð¾Ð´Ð½Ñми паÑамеÑÑами, ÑледÑÑÑим обÑазом:
CREATE TABLE tab (y int, z int);
INSERT INTO tab VALUES (1, 2), (3, 4), (5, 6), (7, 8);
CREATE FUNCTION sum_n_product_with_tab (x int, OUT sum int, OUT product int)
RETURNS SETOF record
AS $$
SELECT $1 + tab.y, $1 * tab.y FROM tab;
$$ LANGUAGE SQL;
SELECT * FROM sum_n_product_with_tab(10);
sum | product
-----+---------
11 | 10
13 | 30
15 | 50
17 | 70
(4 rows) ÐдеÑÑ ÐºÐ»ÑÑÐµÐ²Ð°Ñ Ð¾ÑобенноÑÑÑ Ð·Ð°ÐºÐ»ÑÑаеÑÑÑ Ð² запиÑи RETURNS SETOF record, показÑваÑÑей, ÑÑо ÑÑнкÑÐ¸Ñ Ð²Ð¾Ð·Ð²ÑаÑÐ°ÐµÑ Ð¼Ð½Ð¾Ð¶ÐµÑÑво ÑÑÑок вмеÑÑо одной. ÐÑли ÑÑÑеÑÑвÑÐµÑ ÑолÑко один вÑÑ
одной паÑамеÑÑ, ÑкажиÑе Ñип ÑÑого паÑамеÑÑа вмеÑÑо record.
ЧаÑÑо бÑÐ²Ð°ÐµÑ Ð¿Ð¾Ð»ÐµÐ·Ð½Ð¾ ÑконÑÑÑÑиÑоваÑÑ ÑезÑлÑÑÐ°Ñ Ð·Ð°Ð¿ÑоÑа, вÑзÑÐ²Ð°Ñ ÑÑнкÑиÑ, возвÑаÑаÑÑÑÑ Ð¼Ð½Ð¾Ð¶ÐµÑÑво, неÑколÑко Ñаз, пеÑÐµÐ´Ð°Ð²Ð°Ñ Ð¿Ñи каждом вÑзове паÑамеÑÑÑ Ð¸Ð· оÑеÑеднÑÑ
ÑÑÑок ÑаблиÑÑ Ð¸Ð»Ð¸ подзапÑоÑа. ÐÐ»Ñ ÑÑого ÑекомендÑеÑÑÑ Ð¿ÑимениÑÑ ÐºÐ»ÑÑевое Ñлово LATERAL, опиÑÑваемое в ÐодÑазделе 7.2.1.5. Ðиже пÑиведÑн пÑÐ¸Ð¼ÐµÑ Ð¸ÑполÑÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ ÑÑнкÑии, возвÑаÑаÑÑей множеÑÑво, Ð´Ð»Ñ Ð¿ÐµÑеÑиÑÐ»ÐµÐ½Ð¸Ñ ÑлеменÑов дÑевовидной ÑÑÑÑкÑÑÑÑ:
SELECT * FROM nodes;
name | parent
-----------+--------
Top |
Child1 | Top
Child2 | Top
Child3 | Top
SubChild1 | Child1
SubChild2 | Child1
(6 rows)
CREATE FUNCTION listchildren(text) RETURNS SETOF text AS $$
SELECT name FROM nodes WHERE parent = $1
$$ LANGUAGE SQL STABLE;
SELECT * FROM listchildren('Top');
listchildren
--------------
Child1
Child2
Child3
(3 rows)
SELECT name, child FROM nodes, LATERAL listchildren(name) AS child;
name | child
--------+-----------
Top | Child1
Top | Child2
Top | Child3
Child1 | SubChild1
Child1 | SubChild2
(5 rows)
Ð ÑÑом пÑимеÑе не делаеÑÑÑ Ð½Ð¸Ñего Ñакого, ÑÑо Ð¼Ñ Ð½Ðµ могли Ð±Ñ ÑделаÑÑ, пÑименив пÑоÑÑое Ñоединение, но Ð´Ð»Ñ Ð±Ð¾Ð»ÐµÐµ ÑложнÑÑ Ð²ÑÑиÑлений возможноÑÑÑ Ð¿Ð¾Ð¼ÐµÑÑиÑÑ Ð½ÐµÐºÐ¾ÑоÑÑÑ Ð»Ð¾Ð³Ð¸ÐºÑ Ð² ÑÑнкÑÐ¸Ñ Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð²ÐµÑÑма Ñдобной.
ФÑнкÑии, возвÑаÑаÑÑие множеÑÑва, могÑÑ Ñакже вÑзÑваÑÑÑÑ Ð² ÑпиÑке вÑбоÑки запÑоÑа. ÐÐ»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð¹ ÑÑÑоки, коÑоÑÐ°Ñ Ð³ÐµÐ½ÐµÑиÑÑеÑÑÑ Ñамим запÑоÑом, вÑзÑваеÑÑÑ ÑÑнкÑиÑ, возвÑаÑаÑÑÐ°Ñ Ð¼Ð½Ð¾Ð¶ÐµÑÑво, и Ð´Ð»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð³Ð¾ ÑлеменÑа набоÑа ÐµÑ ÑезÑлÑÑаÑов генеÑиÑÑеÑÑÑ Ð¾ÑделÑÐ½Ð°Ñ ÑÑÑока. ÐÑедÑдÑÑий пÑÐ¸Ð¼ÐµÑ Ð¼Ð¾Ð¶Ð½Ð¾ бÑло Ð±Ñ Ñакже пеÑепиÑаÑÑ Ñ Ð¿Ñименением запÑоÑов ÑледÑÑÑим обÑазом:
SELECT listchildren('Top');
listchildren
--------------
Child1
Child2
Child3
(3 rows)
SELECT name, listchildren(name) FROM nodes;
name | listchildren
--------+--------------
Top | Child1
Top | Child2
Top | Child3
Child1 | SubChild1
Child1 | SubChild2
(5 rows)
ÐамеÑÑÑе, ÑÑо в поÑледней команде SELECT Ð´Ð»Ñ Child2, Child3 и Ñ. д. ÑÑÑоки не вÑдаÑÑÑÑ. ÐÑо пÑоиÑÑ
Ð¾Ð´Ð¸Ñ Ð¿Ð¾ÑомÑ, ÑÑо listchildren возвÑаÑÐ°ÐµÑ Ð¿ÑÑÑое множеÑÑво Ð´Ð»Ñ ÑÑиÑ
аÑгÑменÑов, Ñак ÑÑо ÑÑÑоки ÑезÑлÑÑаÑа не генеÑиÑÑÑÑÑÑ. ÐÑо же поведение Ð¼Ñ Ð¿Ð¾Ð»ÑÑаем пÑи внÑÑÑеннем Ñоединении Ñ ÑезÑлÑÑаÑом ÑÑнкÑии Ñ Ð¿Ñименением LATERAL.
Ðоведение PostgreSQL Ñ ÑÑнкÑиÑми, возвÑаÑаÑÑими множеÑÑва, в ÑпиÑке вÑбоÑки запÑоÑа пÑакÑиÑеÑки не оÑлиÑаеÑÑÑ Ð¾Ñ Ð¿Ð¾Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ñ Ñакими ÑÑнкÑиÑми, помеÑÑннÑми в пÑедложение LATERAL FROM. ÐапÑимеÑ, запÑоÑ:
SELECT x, generate_series(1,5) AS g FROM tab;
поÑÑи ÑавнознаÑен
SELECT x, g FROM tab, LATERAL generate_series(1,5) AS g;
Ðн мог бÑÑÑ Ð¿Ð¾Ð»Ð½Ð¾ÑÑÑÑ Ð¸Ð´ÐµÐ½ÑиÑнÑм, но в данном конкÑеÑном пÑимеÑе планиÑовÑик Ð¼Ð¾Ð¶ÐµÑ ÑеÑиÑÑ Ð¿ÐµÑенеÑÑи g во внеÑнÑÑ ÑÑоÑÐ¾Ð½Ñ ÑоединениÑ, Ñак как g не Ð¸Ð¼ÐµÐµÑ ÑакÑиÑеÑкой завиÑимоÑÑи по вÑемени вÑÑиÑÐ»ÐµÐ½Ð¸Ñ Ð¾Ñ tab. Такое ÑеÑение пÑивело Ð±Ñ Ðº Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð¿Ð¾ÑÑдка ÑÑÑок. ФÑнкÑии, возвÑаÑаÑÑие множеÑÑва, в ÑпиÑке вÑбоÑки вÑегда вÑÑиÑлÑÑÑÑÑ Ñак, как они вÑÑиÑлÑлиÑÑ Ð±Ñ Ð²Ð½ÑÑÑи ÑÐ¾ÐµÐ´Ð¸Ð½ÐµÐ½Ð¸Ñ Ñ Ð²Ð»Ð¾Ð¶ÐµÐ½Ð½Ñм Ñиклом Ñ Ð¾ÑÑалÑнÑм пÑедложением FROM, Ñак ÑÑо ÑÑи ÑÑнкÑии вÑполнÑÑÑÑÑ Ð´Ð¾ завеÑÑÐµÐ½Ð¸Ñ Ð¿Ñежде Ñем наÑинаеÑÑÑ ÑаÑÑмоÑÑение ÑледÑÑÑей ÑÑÑоки из пÑÐµÐ´Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ FROM.
ÐÑли в ÑпиÑке вÑбоÑки запÑоÑа иÑполÑзÑÑÑÑÑ Ð½ÐµÑколÑко ÑÑнкÑий, возвÑаÑаÑÑиÑ
запÑоÑÑ, они вÑÑиÑлÑÑÑÑÑ Ð¿ÑимеÑно Ñак же, как еÑли Ð±Ñ Ð¾Ð½Ð¸ бÑли помеÑÐµÐ½Ñ Ð² один ÑÐ»ÐµÐ¼ÐµÐ½Ñ LATERAL ROWS FROM( ... ) пÑÐµÐ´Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ FROM. ÐÐ»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð¹ ÑÑÑоки из нижележаÑего запÑоÑа вÑдаÑÑÑÑ ÑÑÑока Ñ Ð¿ÐµÑвÑм ÑезÑлÑÑаÑом каждой ÑÑнкÑии, а заÑем ÑÑÑока Ñо вÑоÑÑм ÑезÑлÑÑаÑом и Ñак далее. ÐÑли какие-либо из ÑÑнкÑий, возвÑаÑаÑÑиÑ
множеÑÑва, вÑдаÑÑ Ð¼ÐµÐ½ÑÑе ÑезÑлÑÑаÑов, Ñем дÑÑгие, Ñо вмеÑÑо недоÑÑаÑÑиÑ
даннÑÑ
подÑÑавлÑÑÑÑÑ Ð·Ð½Ð°ÑÐµÐ½Ð¸Ñ NULL, Ñак ÑÑо обÑее ÑиÑло ÑÑÑок, вÑдаваемÑÑ
Ð´Ð»Ñ Ð¾Ð´Ð½Ð¾Ð¹ нижележаÑей ÑÑÑоки, Ñавно ÑиÑÐ»Ñ ÑÑÑок, коÑоÑое вÑдаÑÑ ÑÑнкÑÐ¸Ñ Ñ Ð½Ð°Ð¸Ð±Ð¾Ð»ÑÑим колиÑеÑÑвом ÑÑÑок в возвÑаÑаемом множеÑÑве. Таким обÑазом, ÑÑнкÑии, возвÑаÑаÑÑие множеÑÑва, вÑполнÑÑÑÑÑ ÑовмеÑÑно, пока вÑе иÑ
множеÑÑва не бÑдÑÑ Ð¸ÑÑеÑпанÑ, а заÑем вÑполнение пÑодолжаеÑÑÑ Ñо ÑледÑÑÑей нижележаÑей ÑÑÑокой.
ФÑнкÑии, возвÑаÑаÑÑие множеÑÑва, могÑÑ Ð±ÑÑÑ Ð²Ð»Ð¾Ð¶ÐµÐ½Ð½Ñми в ÑпиÑке вÑбоÑки, но ÑÑо не допÑÑкаеÑÑÑ Ð² ÑлеменÑаÑ
пÑÐµÐ´Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ FROM. Ð ÑакиÑ
ÑлÑÑаÑÑ
каждÑй ÑÑÐ¾Ð²ÐµÐ½Ñ Ð²Ð»Ð¾Ð¶ÐµÐ½Ð½Ð¾ÑÑи обÑабаÑÑваеÑÑÑ Ð¾ÑделÑно, как еÑли Ð±Ñ ÑÑо бÑл оÑделÑнÑй ÑÐ»ÐµÐ¼ÐµÐ½Ñ LATERAL ROWS FROM( ... ). ÐапÑимеÑ, в
SELECT srf1(srf2(x), srf3(y)), srf4(srf5(z)) FROM tab;
возвÑаÑаÑÑие множеÑÑва ÑÑнкÑии srf2, srf3 и srf5 бÑдÑÑ Ð²ÑполнÑÑÑÑÑ ÑовмеÑÑно Ð´Ð»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð¹ ÑÑÑоки tab, а заÑем srf1 и srf4 бÑдÑÑ ÑовмеÑÑно пÑименÑÑÑÑÑ Ðº каждой ÑÑÑоке, пÑоизведÑнной нижними ÑÑнкÑиÑми.
ФÑнкÑии, возвÑаÑаÑÑие множеÑÑва, нелÑÐ·Ñ Ð¸ÑполÑзоваÑÑ Ð² конÑÑÑÑкÑиÑÑ
, вÑÑиÑлÑемÑÑ
по ÑÑловиÑ, напÑимеÑ, CASE или COALESCE. ÐапÑимеÑ, ÑаÑÑмоÑÑиÑе запÑоÑ
SELECT x, CASE WHEN x > 0 THEN generate_series(1, 5) ELSE 0 END FROM tab;
ÐÐ¾Ð¶ÐµÑ Ð¿Ð¾ÐºÐ°Ð·Ð°ÑÑÑÑ, ÑÑо он должен вÑдаÑÑ Ð¿ÑÑÑ ÑкземплÑÑов вÑ
однÑÑ
ÑÑÑок, в коÑоÑÑÑ
x > 0, и по Ð¾Ð´Ð½Ð¾Ð¼Ñ ÑкземплÑÑÑ Ð¾ÑÑалÑнÑÑ
ÑÑÑок; но на деле, Ñак как generate_series(1, 5) бÑÐ´ÐµÑ Ð²ÑполнÑÑÑÑÑ Ð² неÑвном ÑлеменÑе LATERAL FROM до Ñого, как вÑÑажение CASE вообÑе бÑÐ´ÐµÑ ÑаÑÑмаÑÑиваÑÑÑÑ, должно бÑло Ð±Ñ Ð²ÑдаваÑÑÑÑ Ð¿ÑÑÑ ÑкземплÑÑов абÑолÑÑно вÑеÑ
вÑÑ
однÑÑ
ÑÑÑок. Ðо избежание пÑÑаниÑÑ Ð² ÑакиÑ
ÑлÑÑаÑÑ
вÑдаÑÑÑÑ Ð¾Ñибка пÑи ÑазбоÑе запÑоÑа.
ÐÑимеÑание
ÐÑли поÑледнÑÑ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð° ÑÑнкÑии â INSERT, UPDATE, DELETE или MERGE Ñ RETURNING, ÑÑа команда бÑÐ´ÐµÑ Ð²Ñегда вÑполнÑÑÑÑÑ Ð´Ð¾ завеÑÑениÑ, даже еÑли ÑÑнкÑÐ¸Ñ Ð½Ðµ обÑÑвлена Ñ Ñказанием SETOF или вÑзÑваÑÑий запÑÐ¾Ñ Ð½Ðµ вÑбиÑÐ°ÐµÑ Ð²Ñе ÑÑÑоки ÑезÑлÑÑаÑа. ÐÑе дополниÑелÑнÑе ÑÑÑоки, вÑданнÑе пÑедложением RETURNING, пÑоÑÑо игноÑиÑÑÑÑÑÑ, но ÑооÑвеÑÑÑвÑÑÑие Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð² ÑаблиÑе вÑÑ Ñавно пÑоизойдÑÑ (и бÑдÑÑ Ð·Ð°Ð²ÐµÑÑÐµÐ½Ñ Ð´Ð¾ вÑÑ
ода из ÑÑнкÑии).
ÐÑимеÑание
Ð PostgreSQL до веÑÑии 10 пÑи помеÑении неÑколÑкиÑ
ÑÑнкÑий, возвÑаÑаÑÑиÑ
множеÑÑва, в один ÑпиÑок вÑбоÑки поведение бÑло не оÑÐµÐ½Ñ ÑазÑмнÑм, еÑли они возвÑаÑали не одинаковое ÑиÑло ÑÑÑок. Ð ÑакиÑ
ÑлÑÑаÑÑ
ÑиÑло вÑÑ
однÑÑ
ÑÑÑок ÑавнÑлоÑÑ Ð½Ð°Ð¸Ð¼ÐµÐ½ÑÑÐµÐ¼Ñ Ð¾Ð±ÑÐµÐ¼Ñ Ð¼Ð½Ð¾Ð¶Ð¸ÑÐµÐ»Ñ ÐºÐ¾Ð»Ð¸ÑеÑÑв ÑÑÑок, возвÑаÑаемÑÑ
ÑÑими ÑÑнкÑиÑми. Также и вложеннÑе ÑÑнкÑии, возвÑаÑаÑÑие множеÑÑва, ÑабоÑали не Ñак, как опиÑано вÑÑе; Ñ Ñакой ÑÑнкÑии мог бÑÑÑ Ð¼Ð°ÐºÑимÑм один аÑгÑменÑ, возвÑаÑаÑÑий множеÑÑво, и ÐºÐ°Ð¶Ð´Ð°Ñ Ð²Ð»Ð¾Ð¶ÐµÐ½Ð½Ð¾ÑÑÑ Ð²ÑÑиÑлÑлаÑÑ Ð½ÐµÐ·Ð°Ð²Ð¸Ñимо. ÐÑоме Ñого, Ñанее допÑÑкалоÑÑ Ð¸ ÑÑловное вÑполнение (вÑÑиÑление ÑакиÑ
ÑÑнкÑий внÑÑÑи CASE и Ñ. п.), ÑÑо еÑÑ Ð±Ð¾Ð»ÑÑе вÑÑ ÑÑложнÑло. ÐÑи напиÑании запÑоÑов, коÑоÑÑе Ð´Ð¾Ð»Ð¶Ð½Ñ ÑабоÑаÑÑ Ð¸ Ñо ÑÑаÑÑми веÑÑиÑми PostgreSQL, ÑекомендÑеÑÑÑ Ð¸ÑполÑзоваÑÑ ÑинÑакÑÐ¸Ñ LATERAL, Ñак как ÑÑо гаÑанÑиÑÑÐµÑ Ð¾Ð´Ð¸Ð½Ð°ÐºÐ¾Ð²Ñй ÑезÑлÑÑÐ°Ñ Ñ ÑазнÑми веÑÑиÑми. ÐÑли в ваÑем запÑоÑе иÑполÑзÑеÑÑÑ ÑÑловное вÑÑиÑление ÑÑнкÑии, возвÑаÑаÑÑей множеÑÑво, его можно иÑпÑавиÑÑ, пеÑемеÑÑив пÑовеÑÐºÑ ÑÑÐ»Ð¾Ð²Ð¸Ñ Ð² ÑпеÑиалÑно ÑозданнÑÑ ÑÑнкÑиÑ, возвÑаÑаÑÑÑÑ Ð¼Ð½Ð¾Ð¶ÐµÑÑво. ÐапÑимеÑ:
SELECT x, CASE WHEN y > 0 THEN generate_series(1, z) ELSE 5 END FROM tab;
можно замениÑÑ Ð½Ð°
CREATE FUNCTION case_generate_series(cond bool, start int, fin int, els int)
RETURNS SETOF int AS $$
BEGIN
IF cond THEN
RETURN QUERY SELECT generate_series(start, fin);
ELSE
RETURN QUERY SELECT els;
END IF;
END$$ LANGUAGE plpgsql;
SELECT x, case_generate_series(y > 0, 1, z, 5) FROM tab;ÐÑо бÑÐ´ÐµÑ ÑабоÑаÑÑ Ð¾Ð´Ð¸Ð½Ð°ÐºÐ¾Ð²Ð¾ во вÑÐµÑ Ð²ÐµÑÑиÑÑ PostgreSQL.
36.5.10. ФÑнкÑии SQL, возвÑаÑаÑÑие ÑаблиÑÑ (TABLE) #
ÐÑÑÑ ÐµÑÑ Ð¾Ð´Ð¸Ð½ ÑпоÑоб обÑÑвиÑÑ ÑÑнкÑиÑ, возвÑаÑаÑÑÑÑ Ð¼Ð½Ð¾Ð¶ÐµÑÑва, â иÑполÑзоваÑÑ ÑинÑакÑÐ¸Ñ RETURNS TABLE(. ÐÑо ÑавнознаÑно иÑполÑÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¾Ð´Ð½Ð¾Ð³Ð¾ или неÑколÑкиÑ
паÑамеÑÑов ÑÑолбÑÑ)OUT Ñ Ð¾Ð±ÑÑвлением ÑÑнкÑии как возвÑаÑаÑÑей SETOF record (или SETOF Ñип единÑÑвенного паÑамеÑÑа, еÑли ÑÑо пÑименимо). ÐÑÐ¾Ñ ÑинÑакÑÐ¸Ñ Ð¾Ð¿Ð¸Ñан в поÑледниÑ
веÑÑиÑÑ
ÑÑандаÑÑа SQL, Ñак ÑÑо ÑÑÐ¾Ñ Ð²Ð°ÑÐ¸Ð°Ð½Ñ Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð±Ð¾Ð»ÐµÐµ поÑÑиÑÑемÑм, Ñем SETOF.
ÐапÑимеÑ, пÑедÑдÑÑий пÑÐ¸Ð¼ÐµÑ Ñ ÑÑммой и пÑоизведением можно Ñакже пеÑепиÑаÑÑ Ñак:
CREATE FUNCTION sum_n_product_with_tab (x int)
RETURNS TABLE(sum int, product int) AS $$
SELECT $1 + tab.y, $1 * tab.y FROM tab;
$$ LANGUAGE SQL; ÐапиÑÑ RETURNS TABLE не позволÑÐµÑ Ñвно ÑказÑваÑÑ OUT и INOUT Ð´Ð»Ñ Ð¿Ð°ÑамеÑÑов â вÑе вÑÑ
однÑе ÑÑолбÑÑ Ð½ÐµÐ¾Ð±Ñ
одимо запиÑаÑÑ Ð² ÑпиÑке TABLE.
36.5.11. ÐолимоÑÑнÑе ÑÑнкÑии SQL #
ФÑнкÑии SQL могÑÑ Ð±ÑÑÑ Ð¾Ð±ÑÑÐ²Ð»ÐµÐ½Ñ ÐºÐ°Ðº пÑинимаÑÑие и возвÑаÑаÑÑие полимоÑÑнÑе ÑипÑ, опиÑаннÑе в ÐодÑазделе 36.2.5. Ð ÑледÑÑÑем пÑимеÑе полимоÑÑÐ½Ð°Ñ ÑÑнкÑÐ¸Ñ make_array ÑоздаÑÑ Ð¼Ð°ÑÑив из двÑÑ
ÑлеменÑов пÑоизволÑнÑÑ
Ñипов:
CREATE FUNCTION make_array(anyelement, anyelement) RETURNS anyarray AS $$
SELECT ARRAY[$1, $2];
$$ LANGUAGE SQL;
SELECT make_array(1, 2) AS intarray, make_array('a'::text, 'b') AS textarray;
intarray | textarray
----------+-----------
{1,2} | {a,b}
(1 row)
ÐбÑаÑиÑе внимание на пÑиведение Ñипа 'a'::text, опÑеделÑÑÑее, ÑÑо аÑгÑÐ¼ÐµÐ½Ñ Ð¸Ð¼ÐµÐµÑ Ñип text. Ðно необÑ
одимо, еÑли аÑгÑÐ¼ÐµÐ½Ñ Ð·Ð°Ð´Ð°ÑÑÑÑ Ð¿ÑоÑÑо ÑÑÑоковой конÑÑанÑой, Ñак как инаÑе он бÑÐ´ÐµÑ Ð²Ð¾ÑпÑинÑÑ ÐºÐ°Ðº имеÑÑий Ñип unknown, а маÑÑив Ñипов unknown ÑвлÑеÑÑÑ Ð½ÐµÐ´Ð¾Ð¿ÑÑÑимÑм. Ðез ÑÑого пÑÐ¸Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ð²Ñ Ð¿Ð¾Ð»ÑÑиÑе ÑакÑÑ Ð¾ÑибкÑ:
ERROR: could not determine polymorphic type because input has type unknown
(ÐШÐÐÐÐ: не ÑдалоÑÑ Ð¾Ð¿ÑеделиÑÑ Ð¿Ð¾Ð»Ð¸Ð¼Ð¾ÑÑнÑй Ñип, Ñак как Ð²Ñ Ð¾Ð´Ð½Ñе аÑгÑменÑÑ Ð¸Ð¼ÐµÑÑ Ñип unknown)
С показаннÑм вÑÑе обÑÑвлением make_array ÑÑой ÑÑнкÑии нÑжно пÑедоÑÑавиÑÑ Ð´Ð²Ð° аÑгÑменÑа, имеÑÑиÑ
один и ÑÐ¾Ñ Ð¶Ðµ Ñип даннÑÑ
; ÑиÑÑема не бÑÐ´ÐµÑ Ð¿ÑÑаÑÑÑÑ ÑовмеÑаÑÑ ÑазлиÑнÑе ÑипÑ. Так, напÑимеÑ, ÑледÑÑÑий вÑзов не бÑÐ´ÐµÑ ÑабоÑаÑÑ:
SELECT make_array(1, 2.5) AS numericarray; ERROR: function make_array(integer, numeric) does not exist
(ÐШÐÐÐÐ: ÑÑнкÑÐ¸Ñ make_array(integer, numeric) не ÑÑÑеÑÑвÑеÑ) ÐлÑÑеÑнаÑивнÑй Ð¿Ð¾Ð´Ñ Ð¾Ð´ заклÑÑаеÑÑÑ Ð² иÑполÑзовании «обÑего» ÑемейÑÑва полимоÑÑнÑÑ Ñипов; в ÑÑом ÑлÑÑае ÑиÑÑема попÑÑаеÑÑÑ Ð½Ð°Ð¹Ñи Ð¿Ð¾Ð´Ñ Ð¾Ð´ÑÑий обÑий Ñип:
CREATE FUNCTION make_array2(anycompatible, anycompatible)
RETURNS anycompatiblearray AS $$
SELECT ARRAY[$1, $2];
$$ LANGUAGE SQL;
SELECT make_array2(1, 2.5) AS numericarray;
numericarray
--------------
{1,2.5}
(1 row)
Так как пÑавила наÑ
Ð¾Ð¶Ð´ÐµÐ½Ð¸Ñ Ð¾Ð±Ñего Ñипа по ÑмолÑÐ°Ð½Ð¸Ñ ÑводÑÑÑÑ Ðº вÑбоÑÑ Ñипа text, когда вÑе аÑгÑменÑÑ Ð¸Ð¼ÐµÑÑ Ð½ÐµÐ¸Ð·Ð²ÐµÑÑнÑе ÑипÑ, ÑабоÑаÑÑ Ð±ÑÐ´ÐµÑ Ð¸ ÑледÑÑÑий вÑзов:
SELECT make_array2('a', 'b') AS textarray;
textarray
-----------
{a,b}
(1 row)
ФÑнкÑÐ¸Ñ Ñ Ð¿Ð¾Ð»Ð¸Ð¼Ð¾ÑÑнÑми аÑгÑменÑами Ð¼Ð¾Ð¶ÐµÑ Ð¸Ð¼ÐµÑÑ ÑикÑиÑованнÑй Ñип ÑезÑлÑÑаÑа, однако обÑаÑное не допÑÑкаеÑÑÑ. ÐапÑимеÑ:
CREATE FUNCTION is_greater(anyelement, anyelement) RETURNS boolean AS $$
SELECT $1 > $2;
$$ LANGUAGE SQL;
SELECT is_greater(1, 2);
is_greater
------------
f
(1 row)
CREATE FUNCTION invalid_func() RETURNS anyelement AS $$
SELECT 1;
$$ LANGUAGE SQL;
ERROR: cannot determine result data type
DETAIL: A result of type anyelement requires at least one input of type anyelement, anyarray, anynonarray, anyenum, or anyrange.
(ÐШÐÐÐÐ: не ÑдалоÑÑ Ð¾Ð¿ÑеделиÑÑ Ñип ÑезÑлÑÑаÑа; ÐÐÐÐ ÐÐÐÐСТÐ: ÐÐ»Ñ ÑезÑлÑÑаÑа Ñипа anyelement ÑÑебÑеÑÑÑ Ð¼Ð¸Ð½Ð¸Ð¼Ñм один аÑгÑÐ¼ÐµÐ½Ñ Ñипа anyelement, anyarray, anynonarray, anyenum или anyrange.)
ÐолимоÑÑизм можно пÑименÑÑÑ Ð¸ Ñ ÑÑнкÑиÑми, имеÑÑими вÑÑ Ð¾Ð´Ð½Ñе аÑгÑменÑÑ. ÐапÑимеÑ:
CREATE FUNCTION dup (f1 anyelement, OUT f2 anyelement, OUT f3 anyarray)
AS 'select $1, array[$1,$1]' LANGUAGE SQL;
SELECT * FROM dup(22);
f2 | f3
----+---------
22 | {22,22}
(1 row)
ÐолимоÑÑизм Ñакже можно пÑименÑÑÑ Ñ ÑÑнкÑиÑми Ñ Ð¿ÐµÑеменнÑми паÑамеÑÑами. ÐапÑимеÑ:
CREATE FUNCTION anyleast (VARIADIC anyarray) RETURNS anyelement AS $$
SELECT min($1[i]) FROM generate_subscripts($1, 1) g(i);
$$ LANGUAGE SQL;
SELECT anyleast(10, -1, 5, 4);
anyleast
----------
-1
(1 row)
SELECT anyleast('abc'::text, 'def');
anyleast
----------
abc
(1 row)
CREATE FUNCTION concat_values(text, VARIADIC anyarray) RETURNS text AS $$
SELECT array_to_string($2, $1);
$$ LANGUAGE SQL;
SELECT concat_values('|', 1, 4, 2);
concat_values
---------------
1|4|2
(1 row)
36.5.12. ФÑнкÑии SQL Ñ Ð¿Ñавилами ÑоÑÑиÑовки #
Ðогда ÑÑнкÑÐ¸Ñ SQL пÑÐ¸Ð½Ð¸Ð¼Ð°ÐµÑ Ð¾Ð´Ð¸Ð½ или неÑколÑко паÑамеÑÑов ÑоÑÑиÑÑемÑÑ
Ñипов даннÑÑ
, пÑавило ÑоÑÑиÑовки опÑеделÑеÑÑÑ Ð¿Ñи каждом вÑзове ÑÑнкÑии, в завиÑимоÑÑи Ð¾Ñ Ð¿Ñавил ÑоÑÑиÑовки, ÑвÑзаннÑÑ
Ñ ÑакÑиÑеÑкими аÑгÑменÑами, как опиÑано в Разделе 23.2. ÐÑли пÑавило ÑоÑÑиÑовки опÑеделено ÑÑпеÑно (Ñо еÑÑÑ Ð½Ðµ возникло конÑликÑов Ð¼ÐµÐ¶Ð´Ñ Ð½ÐµÑвно ÑÑÑановленнÑми пÑавилами ÑоÑÑиÑовки аÑгÑменÑов), оно неÑвно назнаÑаеÑÑÑ Ð´Ð»Ñ Ð²ÑеÑ
ÑоÑÑиÑÑемÑÑ
паÑамеÑÑов. ÐÑбÑанное пÑавило бÑÐ´ÐµÑ Ð¾Ð¿ÑеделÑÑÑ Ð¿Ð¾Ð²ÐµÐ´ÐµÐ½Ð¸Ðµ опеÑаÑий, ÑвÑзаннÑÑ
Ñ ÑоÑÑиÑовкой, в данной ÑÑнкÑии. ÐапÑимеÑ, Ð´Ð»Ñ Ð¿Ð¾ÐºÐ°Ð·Ð°Ð½Ð½Ð¾Ð¹ вÑÑе ÑÑнкÑии anyleast, ÑезÑлÑÑаÑ
SELECT anyleast('abc'::text, 'ABC'); бÑÐ´ÐµÑ Ð·Ð°Ð²Ð¸ÑеÑÑ Ð¾Ñ Ð¿Ñавила ÑоÑÑиÑовки по ÑмолÑаниÑ, заданного в базе даннÑÑ
. С локалÑÑ C ÑезÑлÑÑаÑом бÑÐ´ÐµÑ ÑÑÑока ABC, но Ñо многими дÑÑгими локалÑми ÑÑо бÑÐ´ÐµÑ abc. ÐÑжное пÑавило ÑоÑÑиÑовки можно ÑÑÑановиÑÑ Ð¿ÑинÑдиÑелÑно, добавив пÑедложение COLLATE к Ð¾Ð´Ð½Ð¾Ð¼Ñ Ð¸Ð· аÑгÑменÑов ÑÑнкÑии, напÑимеÑ:
SELECT anyleast('abc'::text, 'ABC' COLLATE "C"); С дÑÑгой ÑÑоÑонÑ, еÑли Ð²Ñ Ñ
оÑиÑе, ÑÑÐ¾Ð±Ñ ÑÑнкÑÐ¸Ñ ÑабоÑала Ñ Ð¾Ð¿ÑеделÑннÑм пÑавилом ÑоÑÑиÑовки, вне завиÑимоÑÑи Ð¾Ñ Ñого, Ñ ÐºÐ°ÐºÐ¸Ð¼ она бÑла вÑзвана, вÑÑавÑÑе пÑÐµÐ´Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ COLLATE где ÑÑебÑеÑÑÑ Ð² опÑеделении ÑÑнкÑии. ÐÑа веÑÑÐ¸Ñ anyleast вÑегда бÑÐ´ÐµÑ ÑÑавниваÑÑ ÑÑÑоки по пÑавилам локали en_US:
CREATE FUNCTION anyleast (VARIADIC anyarray) RETURNS anyelement AS $$
SELECT min($1[i] COLLATE "en_US") FROM generate_subscripts($1, 1) g(i);
$$ LANGUAGE SQL;Ðо замеÑÑÑе, ÑÑо пÑи попÑÑке пÑимениÑÑ Ð¿Ñавило к неÑоÑÑиÑÑÐµÐ¼Ð¾Ð¼Ñ ÑÐ¸Ð¿Ñ Ð´Ð°Ð½Ð½ÑÑ , Ð²Ð¾Ð·Ð½Ð¸ÐºÐ½ÐµÑ Ð¾Ñибка.
ÐÑли Ð´Ð»Ñ ÑакÑиÑеÑÐºÐ¸Ñ Ð°ÑгÑменÑов не ÑдаÑÑÑÑ Ð¾Ð¿ÑеделиÑÑ Ð¾Ð±Ñее пÑавило ÑоÑÑиÑовки, ÑÑнкÑÐ¸Ñ SQL ÑÑиÑаеÑ, ÑÑо им назнаÑено пÑавило ÑоÑÑиÑовки по ÑмолÑÐ°Ð½Ð¸Ñ Ð´Ð»Ñ Ð¸Ñ Ñипа даннÑÑ (обÑÑно ÑÑо Ñо же пÑавило ÑоÑÑиÑовки, ÑÑо опÑеделено по ÑмолÑÐ°Ð½Ð¸Ñ Ð´Ð»Ñ Ð±Ð°Ð·Ñ Ð´Ð°Ð½Ð½ÑÑ , но оно Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð¸ дÑÑгим Ð´Ð»Ñ Ð¿Ð°ÑамеÑÑов доменнÑÑ Ñипов).
Ðоведение ÑоÑÑиÑÑемÑÑ Ð¿Ð°ÑамеÑÑов можно воÑпÑинимаÑÑ ÐºÐ°Ðº огÑаниÑеннÑÑ ÑоÑÐ¼Ñ Ð¿Ð¾Ð»Ð¸Ð¼Ð¾ÑÑизма, пÑименимÑÑ ÑолÑко к ÑекÑÑовÑм Ñипам даннÑÑ .