F.27. intagg â агÑегаÑÐ¾Ñ Ð¸ нÑмеÑаÑÐ¾Ñ ÑелÑÑ ÑиÑел #
ÐодÑÐ»Ñ intagg пÑедоÑÑавлÑÐµÑ Ð°Ð³ÑегаÑÐ¾Ñ Ð¸ нÑмеÑаÑÐ¾Ñ ÑелÑÑ
ÑиÑел. Ðа даннÑй Ð¼Ð¾Ð¼ÐµÐ½Ñ Ð¸Ð¼ÐµÑÑÑÑ Ð²ÑÑÑоеннÑе ÑÑнкÑии, пÑедлагаÑÑие более ÑиÑокие возможноÑÑи, поÑÑÐ¾Ð¼Ñ intagg ÑÑиÑаеÑÑÑ ÑÑÑаÑевÑим. Ðднако ÑÑÐ¾Ñ Ð¼Ð¾Ð´ÑÐ»Ñ Ð¿ÑÐ¾Ð´Ð¾Ð»Ð¶Ð°ÐµÑ ÑÑÑеÑÑвоваÑÑ Ð´Ð»Ñ Ð¾Ð±ÑаÑной ÑовмеÑÑимоÑÑи, ÑепеÑÑ ÐºÐ°Ðº Ð½Ð°Ð±Ð¾Ñ Ð¾Ð±ÑÑÑок вÑÑÑоеннÑÑ
ÑÑнкÑий.
F.27.1. ФÑнкÑии #
ÐгÑегаÑÐ¾Ñ ÑеализÑеÑÑÑ ÑÑнкÑией int_array_aggregate(integer), коÑоÑÐ°Ñ Ð²ÑдаÑÑ Ð¼Ð°ÑÑив ÑелÑÑ
ÑиÑел, ÑодеÑжаÑий в ÑоÑноÑÑи Ñе ÑиÑла, ÑÑо пеÑÐµÐ´Ð°Ð½Ñ ÐµÐ¹. ÐÑо обÑÑÑка вÑÑÑоенной ÑÑнкÑии array_agg, коÑоÑÐ°Ñ Ð´ÐµÐ»Ð°ÐµÑ Ñо же Ñамое Ð´Ð»Ñ Ð¼Ð°ÑÑива лÑбого Ñипа.
ÐÑмеÑаÑÐ¾Ñ ÑеализÑеÑÑÑ ÑÑнкÑией int_array_enum(integer[]), коÑоÑÐ°Ñ Ð²Ð¾Ð·Ð²ÑаÑÐ°ÐµÑ Ð½Ð°Ð±Ð¾Ñ ÑелÑÑ
(setof integer). Ðо ÑÑÑи его дейÑÑвие обÑаÑно дейÑÑвие агÑегаÑоÑа: полÑÑив маÑÑив ÑелÑÑ
, он ÑазвоÑаÑÐ¸Ð²Ð°ÐµÑ ÐµÐ³Ð¾ в Ð½Ð°Ð±Ð¾Ñ ÑÑÑок. ÐÑо оболоÑка ÑÑнкÑии unnest, коÑоÑÐ°Ñ Ð´ÐµÐ»Ð°ÐµÑ Ñо же Ñамое Ð´Ð»Ñ Ð¼Ð°ÑÑива лÑбого Ñипа.
F.27.2. ÐÑимеÑÑ Ð¸ÑполÑÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ #
Ðо Ð¼Ð½Ð¾Ð³Ð¸Ñ Ð¡Ð£ÐРеÑÑÑ Ð¿Ð¾Ð½ÑÑие ÑаблиÑÑ ÑооÑноÑений «многие ко многим». Ð¢Ð°ÐºÐ°Ñ ÑаблиÑа обÑÑно Ð½Ð°Ñ Ð¾Ð´Ð¸ÑÑÑ Ð¼ÐµÐ¶Ð´Ñ Ð´Ð²ÑÐ¼Ñ Ð¸Ð½Ð´ÐµÐºÑиÑованнÑми ÑаблиÑами, напÑимеÑ:
CREATE TABLE left_table (id INT PRIMARY KEY, ...);
CREATE TABLE right_table (id INT PRIMARY KEY, ...);
CREATE TABLE many_to_many(id_left INT REFERENCES left_table,
id_right INT REFERENCES right_table);Ðак пÑавило, она иÑполÑзÑеÑÑÑ Ñак:
SELECT right_table.*
FROM right_table JOIN many_to_many ON (right_table.id = many_to_many.id_right)
WHERE many_to_many.id_left = ÑлеменÑ;ÐÑÐ¾Ñ Ð·Ð°Ð¿ÑÐ¾Ñ Ð²ÐµÑнÑÑ Ð²Ñе ÑлеменÑÑ Ð¸Ð· ÑаблиÑÑ ÑпÑава Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñи в ÑаблиÑе Ñлева. ÐÑо оÑÐµÐ½Ñ ÑаÑпÑоÑÑÑанÑÐ½Ð½Ð°Ñ ÐºÐ¾Ð½ÑÑÑÑкÑÐ¸Ñ Ð² SQL.
Ðднако ÑÑÐ¾Ñ Ð¿Ð¾Ð´Ñ
од Ð¼Ð¾Ð¶ÐµÑ Ð²ÑзÑваÑÑ Ð·Ð°ÑÑÑÐ´Ð½ÐµÐ½Ð¸Ñ Ñ Ð¾ÑÐµÐ½Ñ Ð±Ð¾Ð»ÑÑим колиÑеÑÑвом запиÑей в ÑаблиÑе many_to_many. ЧаÑÑо Ñакое Ñоединение влеÑÑÑ ÑканиÑование индекÑа и вÑбоÑÐºÑ ÐºÐ°Ð¶Ð´Ð¾Ð¹ запиÑи в ÑаблиÑе ÑпÑава Ð´Ð»Ñ ÐºÐ¾Ð½ÐºÑеÑного ÑлеменÑа Ñлева. ÐÑли Ñ Ð²Ð°Ñ Ð´Ð¸Ð½Ð°Ð¼Ð¸ÑеÑÐºÐ°Ñ ÑиÑÑема, Ñ ÑÑим ниÑего не поделаÑÑ. Ðо еÑли какое-Ñо множеÑÑво даннÑÑ
доволÑно ÑÑаÑиÑеÑкое, Ð²Ñ Ð¼Ð¾Ð¶ÐµÑе ÑоздаÑÑ ÑводнÑÑ ÑаблиÑÑ, пÑименив агÑегаÑоÑ.
CREATE TABLE summary AS SELECT id_left, int_array_aggregate(id_right) AS rights FROM many_to_many GROUP BY id_left;
ÐÑа команда ÑоздаÑÑ ÑаблиÑÑ, ÑодеÑжаÑÑÑ Ð¾Ð´Ð½Ñ ÑÑÑÐ¾ÐºÑ Ð´Ð»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð³Ð¾ ÑлеменÑа Ñлева Ñ Ð¼Ð°ÑÑивом ÑлеменÑов ÑпÑава. Ðна малополезна, пока не найден Ð¿Ð¾Ð´Ñ Ð¾Ð´ÑÑий ÑпоÑоб иÑполÑÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ ÑÑого маÑÑива; именно Ð´Ð»Ñ ÑÑого и нÑжен нÑмеÑаÑÐ¾Ñ Ð¼Ð°ÑÑива. ÐÑ Ð¼Ð¾Ð¶ÐµÑе вÑполниÑÑ:
SELECT id_left, int_array_enum(rights) FROM summary WHERE id_left = ÑлеменÑ; ÐÑиведÑннÑй вÑÑе запÑÐ¾Ñ Ñ Ð²Ñзовом int_array_enum вÑдаÑÑ Ñе же ÑезÑлÑÑаÑÑ, ÑÑо и
SELECT id_left, id_right FROM many_to_many WHERE id_left = ÑлеменÑ; ÐÑлиÑие ÑоÑÑÐ¾Ð¸Ñ Ð² Ñом, ÑÑо запÑÐ¾Ñ Ðº Ñводной ÑаблиÑе должен вÑдаÑÑ ÑолÑко Ð¾Ð´Ð½Ñ ÑÑÑÐ¾ÐºÑ ÑаблиÑÑ, Ñогда как непоÑÑедÑÑвеннÑй запÑÐ¾Ñ Ðº many_to_many поÑÑебÑÐµÑ ÑканиÑÐ¾Ð²Ð°Ð½Ð¸Ñ Ð¸Ð½Ð´ÐµÐºÑа и вÑбоÑки ÑÑÑоки Ð´Ð»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð¹ запиÑи.
Ðа ÑеÑÑовом компÑÑÑеÑе команда EXPLAIN показала, ÑÑо ÑÑоимоÑÑÑ Ð·Ð°Ð¿ÑоÑа ÑнизилаÑÑ Ñ 8488 до 329. ÐÑÑ
однÑй запÑÐ¾Ñ Ð²ÑполнÑл Ñоединение Ñ ÑаблиÑей many_to_many и бÑл заменÑн на:
SELECT id_right, count(id_right) FROM
( SELECT id_left, int_array_enum(rights) AS id_right
FROM summary
JOIN (SELECT id FROM left_table
WHERE id = ÑлеменÑ) AS lefts
ON (summary.id_left = lefts.id)
) AS list
GROUP BY id_right
ORDER BY count DESC;