рдпрд╕ рд╕рдореНрдмрдиреНрдзрдорд╛ DBMS рд▓реЗ рд╕рдорд╛рди рд╕рд┐рджреНрдзрд╛рдиреНрддрд╣рд░реВрдорд╛ рдХрд╛рдо рдЧрд░реНрджрдЫ - "рддрд┐рдиреАрд╣рд░реВрд▓реЗ рдорд▓рд╛рдИ рдЦрдиреНрди рднрдиреЗ, рддреНрдпрд╕реИрд▓реЗ рдореИрд▓реЗ рдЦрдиреНрдиреЗ"ред рддрдкрд╛рдИрдВрдХреЛ рдЕрдиреБрд░реЛрдзрд▓реЗ рдЫрд┐рдореЗрдХреА рдкреНрд░рдХреНрд░рд┐рдпрд╛рд╣рд░реВ рдорд╛рддреНрд░ рдврд┐рд▓реЛ рдЧрд░реНрди рд╕рдХреНрджреИрди, рдирд┐рд░рдиреНрддрд░ рдкреНрд░реЛрд╕реЗрд╕рд░ рд╕реНрд░реЛрддрд╣рд░реВ рд▓рд┐рдиреНрдЫ, рддрд░ рд╕рдореНрдкреВрд░реНрдг рдбрд╛рдЯрд╛рдмреЗрд╕рд▓рд╛рдИ "рдбреНрд░рдк" рдЧрд░реНрди рд╕рдХреНрдЫ, рд╕рдмреИ рдЙрдкрд▓рдмреНрдз рдореЗрдореЛрд░реА "рдЦрд╛рдиреЗ"ред рдЕрдирдиреНрдд рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ рд╡рд┐рд░реБрджреНрдз рд╕реБрд░рдХреНрд╖рд╛ - рд╡рд┐рдХрд╛рд╕рдХрд░реНрддрд╛ рдЖрдлреИрдВрдХреЛ рдЬрд┐рдореНрдореЗрд╡рд╛рд░реАред
PostgreSQL рдорд╛, рдорд╛рд░реНрдлрдд рдкреБрдирд░рд╛рд╡рд░реНрддреА рдкреНрд░рд╢реНрдирд╣рд░реВ рдкреНрд░рдпреЛрдЧ рдЧрд░реНрдиреЗ рдХреНрд╖рдорддрд╛ WITH RECURSIVE
рдкреБрдирд░рд╛рд╡рд░реНрддреА рдкреНрд░рд╢реНрдирд╣рд░реВ рдирд▓реЗрдЦреНрдиреБрд╣реЛрд╕реН
рд░ рдЧреИрд░-рдкреБрдирд░рд╛рд╡рд░реНрддреА рд▓реЗрдЦреНрдиреБрд╣реЛрд╕реНред рднрд╡рджреАрдп, рддрдкрд╛рдИрдХреЛ K.O.
рд╡рд╛рд╕реНрддрд╡рдорд╛, PostgreSQL рд▓реЗ рддрдкрд╛рдИрд▓реЗ рдкреНрд░рдпреЛрдЧ рдЧрд░реНрди рд╕рдХреНрдиреЗ рдзреЗрд░реИ рдкреНрд░рдХрд╛рд░реНрдпрддрд╛ рдкреНрд░рджрд╛рди рдЧрд░реНрджрдЫ рдЫреИрди рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ рд▓рд╛рдЧреВ рдЧрд░реНрдиреБрд╣реЛрд╕реНред
рд╕рдорд╕реНрдпрд╛рдХреЛ рд▓рд╛рдЧрд┐ рдореМрд▓рд┐рдХ рд░реВрдкрдорд╛ рдлрд░рдХ рджреГрд╖реНрдЯрд┐рдХреЛрдг рдкреНрд░рдпреЛрдЧ рдЧрд░реНрдиреБрд╣реЛрд╕реН
рдХрд╣рд┐рд▓реЗрдХрд╛рд╣реАрдБ рддрдкрд╛рдИрд▓реЗ рд╕рдорд╕реНрдпрд╛рд▓рд╛рдИ "рднрд┐рдиреНрди рдкрдХреНрд╖" рдмрд╛рдЯ рд╣реЗрд░реНрди рд╕рдХреНрдиреБрд╣реБрдиреНрдЫред рдореИрд▓реЗ рд▓реЗрдЦрдорд╛ рдпрд╕реНрддреЛ рдЕрд╡рд╕реНрдерд╛рдХреЛ рдЙрджрд╛рд╣рд░рдг рджрд┐рдПрдБ
WITH RECURSIVE src AS (
SELECT '{2,3,5,7,11,13,17,19}'::integer[] arr
)
, T(i, val) AS (
SELECT
1::bigint
, 1
UNION ALL
SELECT
i + 1
, val * arr[i]
FROM
T
, src
WHERE
i <= array_length(arr, 1)
)
SELECT
val
FROM
T
ORDER BY -- ╨╛╤В╨▒╨╛╤А ╤Д╨╕╨╜╨░╨╗╤М╨╜╨╛╨│╨╛ ╤А╨╡╨╖╤Г╨╗╤М╤В╨░╤В╨░
i DESC
LIMIT 1;
рдпреЛ рдЕрдиреБрд░реЛрдз рдЧрдгрд┐рдд рд╡рд┐рд╢реЗрд╖рдЬреНрдЮрд╣рд░реБ рдХреЛ рдПрдХ рд╡рд┐рдХрд▓реНрдк рд╕рдВрдЧ рдкреНрд░рддрд┐рд╕реНрдерд╛рдкрд┐рдд рдЧрд░реНрди рд╕рдХрд┐рдиреНрдЫ:
WITH src AS (
SELECT unnest('{2,3,5,7,11,13,17,19}'::integer[]) prime
)
SELECT
exp(sum(ln(prime)))::integer val
FROM
src;
loops рдХреЛ рд╕рдЯреНрдЯрд╛ generate_series рдкреНрд░рдпреЛрдЧ рдЧрд░реНрдиреБрд╣реЛрд╕реН
рдорд╛рдиреМрдВ рд╣рд╛рдореА рд╕реНрдЯреНрд░рд┐рдЩрдХрд╛ рд▓рд╛рдЧрд┐ рд╕рдмреИ рд╕рдореНрднрд╛рд╡рд┐рдд рдЙрдкрд╕рд░реНрдЧрд╣рд░реВ рдЙрддреНрдкрдиреНрди рдЧрд░реНрдиреЗ рдХрд╛рд░реНрдпрдХреЛ рд╕рд╛рдордирд╛ рдЧрд░рд┐рд░рд╣реЗрдХрд╛ рдЫреМрдВ 'abcdefgh'
:
WITH RECURSIVE T AS (
SELECT 'abcdefgh' str
UNION ALL
SELECT
substr(str, 1, length(str) - 1)
FROM
T
WHERE
length(str) > 1
)
TABLE T;
рдХреЗ рддрдкрд╛рдЗрдБ рдирд┐рд╢реНрдЪрд┐рдд рд╣реБрдиреБрд╣реБрдиреНрдЫ рдХрд┐ рддрдкрд╛рдЗрдБ рдпрд╣рд╛рдБ рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ рдЪрд╛рд╣рд┐рдиреНрдЫ?... рдпрджрд┐ рддрдкрд╛рдЗрдБ рдкреНрд░рдпреЛрдЧ рдЧрд░реНрдиреБрд╣реБрдиреНрдЫ рднрдиреЗ LATERAL
╨╕ generate_series
, рддрдм рддрдкрд╛рдИрд▓рд╛рдИ CTE рдХреЛ рдЖрд╡рд╢реНрдпрдХрддрд╛ рдкрд░реНрджреИрди:
SELECT
substr(str, 1, ln) str
FROM
(VALUES('abcdefgh')) T(str)
, LATERAL(
SELECT generate_series(length(str), 1, -1) ln
) X;
рдбрд╛рдЯрд╛рдмреЗрд╕ рд╕рдВрд░рдЪрдирд╛ рдкрд░рд┐рд╡рд░реНрддрди рдЧрд░реНрдиреБрд╣реЛрд╕реН
рдЙрджрд╛рд╣рд░рдгрдХрд╛ рд▓рд╛рдЧрд┐, рддрдкрд╛рдИрдВрд╕рдБрдЧ рдХрд╕рд▓реЗ рдХрд╕рд▓рд╛рдИ рдЬрд╡рд╛рдл рджрд┐рдпреЛ, рд╡рд╛ рдереНрд░реЗрдбрдорд╛ рдЬрдбрд╛рди рднрдПрдХреЛ рдлреЛрд░рдо рд╕рдиреНрджреЗрд╢рд╣рд░реВрдХреЛ рддрд╛рд▓рд┐рдХрд╛ рдЫред
CREATE TABLE message(
message_id
uuid
PRIMARY KEY
, reply_to
uuid
REFERENCES message
, body
text
);
CREATE INDEX ON message(reply_to);
рдард┐рдХ рдЫ, рдПрдЙрдЯрд╛ рд╢реАрд░реНрд╖рдХрдорд╛ рд╕рдмреИ рд╕рдиреНрджреЗрд╢рд╣рд░реВ рдбрд╛рдЙрдирд▓реЛрдб рдЧрд░реНрдирдХреЛ рд▓рд╛рдЧрд┐ рд╕рд╛рдорд╛рдиреНрдп рдЕрдиреБрд░реЛрдз рдпрд╕реНрддреЛ рджреЗрдЦрд┐рдиреНрдЫ:
WITH RECURSIVE T AS (
SELECT
*
FROM
message
WHERE
message_id = $1
UNION ALL
SELECT
m.*
FROM
T
JOIN
message m
ON m.reply_to = T.message_id
)
TABLE T;
рддрд░ рд╣рд╛рдореАрд▓рд╛рдИ рдЬрд╣рд┐рд▓реЗ рдкрдирд┐ рдореВрд▓ рд╕рдиреНрджреЗрд╢рдмрд╛рдЯ рд╕рдореНрдкреВрд░реНрдг рд╡рд┐рд╖рдп рдЪрд╛рд╣рд┐рдиреНрдЫ, рддреНрдпрд╕реЛрднрдП рд╣рд╛рдореА рдХрд┐рди рдЧрд░реНрджреИрдиреМрдВ рдкреНрд░рддреНрдпреЗрдХ рдкреНрд░рд╡рд┐рд╖реНрдЯрд┐рдорд╛ рдпрд╕рдХреЛ рдЖрдИрдбреА рдердкреНрдиреБрд╣реЛрд╕реН рд╕реНрд╡рдЪрд╛рд▓рд┐рдд?
-- ╨┤╨╛╨▒╨░╨▓╨╕╨╝ ╨┐╨╛╨╗╨╡ ╤Б ╨╛╨▒╤Й╨╕╨╝ ╨╕╨┤╨╡╨╜╤В╨╕╤Д╨╕╨║╨░╤В╨╛╤А╨╛╨╝ ╤В╨╡╨╝╤Л ╨╕ ╨╕╨╜╨┤╨╡╨║╤Б ╨╜╨░ ╨╜╨╡╨│╨╛
ALTER TABLE message
ADD COLUMN theme_id uuid;
CREATE INDEX ON message(theme_id);
-- ╨╕╨╜╨╕╤Ж╨╕╨░╨╗╨╕╨╖╨╕╤А╤Г╨╡╨╝ ╨╕╨┤╨╡╨╜╤В╨╕╤Д╨╕╨║╨░╤В╨╛╤А ╤В╨╡╨╝╤Л ╨▓ ╤В╤А╨╕╨│╨│╨╡╤А╨╡ ╨┐╤А╨╕ ╨▓╤Б╤В╨░╨▓╨║╨╡
CREATE OR REPLACE FUNCTION ins() RETURNS TRIGGER AS $$
BEGIN
NEW.theme_id = CASE
WHEN NEW.reply_to IS NULL THEN NEW.message_id -- ╨▒╨╡╤А╨╡╨╝ ╨╕╨╖ ╤Б╤В╨░╤А╤В╨╛╨▓╨╛╨│╨╛ ╤Б╨╛╨▒╤Л╤В╨╕╤П
ELSE ( -- ╨╕╨╗╨╕ ╨╕╨╖ ╤Б╨╛╨╛╨▒╤Й╨╡╨╜╨╕╤П, ╨╜╨░ ╨║╨╛╤В╨╛╤А╨╛╨╡ ╨╛╤В╨▓╨╡╤З╨░╨╡╨╝
SELECT
theme_id
FROM
message
WHERE
message_id = NEW.reply_to
)
END;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER ins BEFORE INSERT
ON message
FOR EACH ROW
EXECUTE PROCEDURE ins();
рдЕрдм рд╣рд╛рдореНрд░реЛ рд╕рдореНрдкреВрд░реНрдг рдкреБрдирд░рд╛рд╡рд░реНрддреА рдХреНрд╡реЗрд░реАрд▓рд╛рдИ рдпреЛ рдорд╛рддреНрд░рдорд╛ рдХрдо рдЧрд░реНрди рд╕рдХрд┐рдиреНрдЫ:
SELECT
*
FROM
message
WHERE
theme_id = $1;
рд▓рд╛рдЧреВ "рд╕реАрдорд╛рд╣рд░реВ" рдкреНрд░рдпреЛрдЧ рдЧрд░реНрдиреБрд╣реЛрд╕реН
рдпрджрд┐ рд╣рд╛рдореА рдХреБрдиреИ рдХрд╛рд░рдгрд▓реЗ рдбрд╛рдЯрд╛рдмреЗрд╕рдХреЛ рд╕рдВрд░рдЪрдирд╛ рдкрд░рд┐рд╡рд░реНрддрди рдЧрд░реНрди рдЕрд╕рдорд░реНрде рдЫреМрдВ рднрдиреЗ, рд╣рд╛рдореА рдХреЗрдорд╛ рднрд░ рдкрд░реНрди рд╕рдХреНрдЫреМрдВ рднрдиреЗрд░ рд╣реЗрд░реМрдВ рддрд╛рдХрд┐ рдбрд╛рдЯрд╛рдорд╛ рддреНрд░реБрдЯрд┐рдХреЛ рдЙрдкрд╕реНрдерд┐рддрд┐рд▓реЗ рдкрдирд┐ рдЕрдирдиреНрдд рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐рдХреЛ рдиреЗрддреГрддреНрд╡ рдЧрд░реНрджреИрдиред
рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ рдЧрд╣рд┐рд░рд╛рдИ рдХрд╛рдЙрдиреНрдЯрд░
рд╣рд╛рдореА рдкреНрд░рддреНрдпреЗрдХ рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ рдЪрд░рдгрдорд╛ рдПрдХрд▓реЗ рдХрд╛рдЙрдиреНрдЯрд░ рдмрдврд╛рдЙрдБрдЫреМрдВ рдЬрдмрд╕рдореНрдо рд╣рд╛рдореА рд╕реНрдкрд╖реНрдЯ рд░реВрдкрдорд╛ рдЕрдкрд░реНрдпрд╛рдкреНрдд рдорд╛рдиреНрдиреЗ рд╕реАрдорд╛рдорд╛ рдкреБрдЧреНрджреИрдиреМрдВ:
WITH RECURSIVE T AS (
SELECT
0 i
...
UNION ALL
SELECT
i + 1
...
WHERE
T.i < 64 -- ╨┐╤А╨╡╨┤╨╡╨╗
)
рдкреНрд░реЛ: рдЬрдм рд╣рд╛рдореА рд▓реБрдк рдЧрд░реНрдиреЗ рдкреНрд░рдпрд╛рд╕ рдЧрд░реНрдЫреМрдВ, рд╣рд╛рдореА рдЕрдЭреИ рдкрдирд┐ "рдЧрд╣рд┐рд░рд╛рдЗрдорд╛" рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐рдХреЛ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рд╕реАрдорд╛ рднрдиреНрджрд╛ рдмрдвреА рдЧрд░реНрджреИрдиреМрдВред
рд╡рд┐рдкрдХреНрд╖: рддреНрдпрд╣рд╛рдБ рдХреБрдиреИ рдЧреНрдпрд╛рд░реЗрдиреНрдЯреА рдЫреИрди рдХрд┐ рд╣рд╛рдореАрд▓реЗ рдЙрд╣реА рд░реЗрдХрд░реНрдбрд▓рд╛рдИ рдлреЗрд░рд┐ рдкреНрд░рд╢реЛрдзрди рдЧрд░реНрдиреЗ рдЫреИрдиреМрдВ - рдЙрджрд╛рд╣рд░рдгрдХрд╛ рд▓рд╛рдЧрд┐, 15 рд░ 25 рдХреЛ рдЧрд╣рд┐рд░рд╛рдЗрдорд╛, рд░ рддреНрдпрд╕рдкрдЫрд┐ рдкреНрд░рддреНрдпреЗрдХ +10ред рд░ рдХрд╕реИрд▓реЗ рдкрдирд┐ "рдЪреМрдбрд╛рдИ" рдХреЛ рдмрд╛рд░реЗ рдорд╛ рдХреЗрд╣рд┐ рдкреНрд░рддрд┐рдЬреНрдЮрд╛ рдЧрд░реЗрдиред
рдФрдкрдЪрд╛рд░рд┐рдХ рд░реВрдкрдорд╛, рдпрд╕реНрддреЛ рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ рдЕрд╕реАрдо рд╣реБрдиреЗрдЫреИрди, рддрд░ рдпрджрд┐ рдкреНрд░рддреНрдпреЗрдХ рдЪрд░рдгрдорд╛ рд░реЗрдХрд░реНрдбрд╣рд░реВрдХреЛ рд╕рдВрдЦреНрдпрд╛ рджреНрд░реБрдд рд░реВрдкрдорд╛ рдмрдвреНрдЫ, рд╣рд╛рдореА рд╕рдмреИрд▓рд╛рдИ рд░рд╛рдореНрд░рд░реА рдерд╛рд╣рд╛ рдЫ рдХрд┐ рдпреЛ рдХрд╕рд░реА рд╕рдорд╛рдкреНрдд рд╣реБрдиреНрдЫ ...
"рдорд╛рд░реНрдЧ" рдХреЛ рд╕рдВрд░рдХреНрд╖рдХ
рд╣рд╛рдореА рд╡реИрдХрд▓реНрдкрд┐рдХ рд░реВрдкрдорд╛ рдПрд░реЗрдорд╛ рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ рдорд╛рд░реНрдЧрдорд╛ рд╕рд╛рдордирд╛ рдЧрд░реЗрдХрд╛ рд╕рдмреИ рд╡рд╕реНрддреБ рдкрд╣рд┐рдЪрд╛рдирдХрд░реНрддрд╛рд╣рд░реВ рдердкреНрдЫреМрдВ, рдЬреБрди рдпрд╕рдХреЛ рд▓рд╛рдЧрд┐ рдПрдХ рдЕрджреНрд╡рд┐рддреАрдп "рдорд╛рд░реНрдЧ" рд╣реЛ:
WITH RECURSIVE T AS (
SELECT
ARRAY[id] path
...
UNION ALL
SELECT
path || id
...
WHERE
id <> ALL(T.path) -- ╨╜╨╡ ╤Б╨╛╨▓╨┐╨░╨┤╨░╨╡╤В ╨╜╨╕ ╤Б ╨╛╨┤╨╜╨╕╨╝ ╨╕╨╖
)
рдкреНрд░реЛ: рдпрджрд┐ рдбреЗрдЯрд╛рдорд╛ рдПрдХ рдЪрдХреНрд░ рдЫ рднрдиреЗ, рд╣рд╛рдореА рдмрд┐рд▓реНрдХреБрд▓ рдПрдЙрдЯреИ рд░реЗрдХрд░реНрдбрд▓рд╛рдИ рдПрдЙрдЯреИ рдорд╛рд░реНрдЧ рднрд┐рддреНрд░ рдмрд╛рд░рдореНрдмрд╛рд░ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдЧрд░реНрджреИрдиреМрдВред
рд╡рд┐рдкрдХреНрд╖: рддрд░ рдПрдХреИ рд╕рдордпрдорд╛, рд╣рд╛рдореА рд╢рд╛рдмреНрджрд┐рдХ рд░реВрдкрдорд╛ рдЖрдлреИрд▓рд╛рдИ рджреЛрд╣реЛрд░реНрдпрд╛рдЙрди рдмрд┐рдирд╛ рд╕рдмреИ рд░реЗрдХрд░реНрдбрд╣рд░реВ рдмрд╛рдЗрдкрд╛рд╕ рдЧрд░реНрди рд╕рдХреНрдЫреМрдВред
рдкрде рд▓рдореНрдмрд╛рдЗ рд╕реАрдорд╛
рдмреБрдЭреНрди рдирд╕рдХрд┐рдиреЗ рдЧрд╣рд┐рд░рд╛рдЗрдорд╛ рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ "рднрдЯрдХ" рдХреЛ рд╕реНрдерд┐рддрд┐рдмрд╛рдЯ рдмрдЪреНрди, рд╣рд╛рдореА рджреБрдИ рдЕрдШрд┐рд▓реНрд▓реЛ рд╡рд┐рдзрд┐рд╣рд░реВ рд╕рдВрдпреЛрдЬрди рдЧрд░реНрди рд╕рдХреНрдЫреМрдВред рд╡рд╛, рдпрджрд┐ рд╣рд╛рдореА рдЕрдирд╛рд╡рд╢реНрдпрдХ рдХреНрд╖реЗрддреНрд░рд╣рд░реВрд▓рд╛рдИ рд╕рдорд░реНрдерди рдЧрд░реНрди рдЪрд╛рд╣рдБрджреИрдиреМрдВ рднрдиреЗ, рдкрде рд▓рдореНрдмрд╛рдЗрдХреЛ рдЕрдиреБрдорд╛рдирдХреЛ рд╕рд╛рде рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ рдЬрд╛рд░реА рд░рд╛рдЦреНрдирдХреЛ рд▓рд╛рдЧрд┐ рд╕рд░реНрддрдХреЛ рдкреВрд░реНрддрд┐ рдЧрд░реНрдиреБрд╣реЛрд╕реН:
WITH RECURSIVE T AS (
SELECT
ARRAY[id] path
...
UNION ALL
SELECT
path || id
...
WHERE
id <> ALL(T.path) AND
array_length(T.path, 1) < 10
)
рдЖрдлреНрдиреЛ рд╕реНрд╡рд╛рдж рдХреЛ рд▓рд╛рдЧреА рдПрдХ рд╡рд┐рдзрд┐ рдЫрд╛рдиреНрдиреБрд╣реЛрд╕реН!
рд╕реНрд░реЛрдд: www.habr.com