PostgreSQL рдПрдВрдЯреАрдкреИрдЯрд░реНрди: "рдЕрдирдВрдд рд╕реАрдорд╛ рдирд╣реАрдВ рд╣реИ!", рдпрд╛ рд░рд┐рдХрд░реНрд╕рди рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдереЛрдбрд╝рд╛ рд╕рд╛

рдкреНрд░рддреНрдпрд╛рд╡рд░реНрддрди - рдпрджрд┐ рд╕рдВрдмрдВрдзрд┐рдд рдбреЗрдЯрд╛ рдкрд░ рд╕рдорд╛рди "рдЧрд╣рди" рдХреНрд░рд┐рдпрд╛рдПрдВ рдХреА рдЬрд╛рддреА рд╣реИрдВ рддреЛ рдПрдХ рдмрд╣реБрдд рд╢рдХреНрддрд┐рд╢рд╛рд▓реА рдФрд░ рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рддрдВрддреНрд░ред рд▓реЗрдХрд┐рди рдЕрдирд┐рдпрдВрддреНрд░рд┐рдд рдкреБрдирд░рд╛рд╡рд░реНрддрди рдПрдХ рдРрд╕реА рдмреБрд░рд╛рдИ рд╣реИ рдЬреЛ рджреЛрдиреЛрдВ рдореЗрдВ рд╕реЗ рдХрд┐рд╕реА рдПрдХ рдХреЛ рдЬрдиреНрдо рджреЗ рд╕рдХрддреА рд╣реИ рдЕрдВрддрд╣реАрди рдирд┐рд╖реНрдкрд╛рджрди рдкреНрд░рдХреНрд░рд┐рдпрд╛, рдпрд╛ (рдЬреЛ рдЕрдзрд┐рдХ рдмрд╛рд░ рд╣реЛрддрд╛ рд╣реИ)ред рд╕рднреА рдЙрдкрд▓рдмреНрдз рдореЗрдореЛрд░реА рдХреЛ "рдЦрд╛рдирд╛"ред.

PostgreSQL рдПрдВрдЯреАрдкреИрдЯрд░реНрди: "рдЕрдирдВрдд рд╕реАрдорд╛ рдирд╣реАрдВ рд╣реИ!", рдпрд╛ рд░рд┐рдХрд░реНрд╕рди рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдереЛрдбрд╝рд╛ рд╕рд╛
рдЗрд╕ рд╕рдВрдмрдВрдз рдореЗрдВ DBMS рдЗрдиреНрд╣реАрдВ рд╕рд┐рджреНрдзрд╛рдВрддреЛрдВ рдкрд░ рдХрд╛рд░реНрдп рдХрд░рддрд╛ рд╣реИ - "рдЙрдиреНрд╣реЛрдВрдиреЗ рдореБрдЭрд╕реЗ рдЦреБрджрд╛рдИ рдХрд░рдиреЗ рдХреЛ рдХрд╣рд╛, рдЗрд╕рд▓рд┐рдП рдореИрдВрдиреЗ рдЦреБрджрд╛рдИ рдХреА"ред рдЖрдкрдХрд╛ рдЕрдиреБрд░реЛрдз рди рдХреЗрд╡рд▓ рдкрдбрд╝реЛрд╕реА рдкреНрд░рдХреНрд░рд┐рдпрд╛рдУрдВ рдХреЛ рдзреАрдорд╛ рдХрд░ рд╕рдХрддрд╛ рд╣реИ, рд▓рдЧрд╛рддрд╛рд░ рдкреНрд░реЛрд╕реЗрд╕рд░ рд╕рдВрд╕рд╛рдзрди рд▓реЗ рд╕рдХрддрд╛ рд╣реИ, рдмрд▓реНрдХрд┐ рдкреВрд░реЗ рдбреЗрдЯрд╛рдмреЗрд╕ рдХреЛ "рдЫреЛрдбрд╝" рднреА рд╕рдХрддрд╛ рд╣реИ, рд╕рднреА рдЙрдкрд▓рдмреНрдз рдореЗрдореЛрд░реА рдХреЛ "рдЦрд╛" рд╕рдХрддрд╛ рд╣реИред рдЗрд╕рд▓рд┐рдП рдЕрдирдВрдд рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ рдХреЗ рд╡рд┐рд░реБрджреНрдз рд╕реБрд░рдХреНрд╖рд╛ - рдЬрд┐рдореНрдореЗрджрд╛рд░реА рд╕реНрд╡рдпрдВ рдбреЗрд╡рд▓рдкрд░ рдХреАред

PostgreSQL рдореЗрдВ, рдкреБрдирд░рд╛рд╡рд░реНрддреА рдкреНрд░рд╢реНрдиреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреА рдХреНрд╖рдорддрд╛ WITH RECURSIVE рд╕рдВрд╕реНрдХрд░рдг 8.4 рдХреЗ рдкреНрд░рд╛рдЪреАрди рд╕рдордп рдореЗрдВ рджрд┐рдЦрд╛рдИ рджрд┐рдпрд╛, рд▓реЗрдХрд┐рди рдЖрдк рдЕрднреА рднреА рдирд┐рдпрдорд┐рдд рд░реВрдк рд╕реЗ рд╕рдВрднрд╛рд╡рд┐рдд рд░реВрдк рд╕реЗ рдХрдордЬреЛрд░ "рд░рдХреНрд╖рд╛рд╣реАрди" рдЕрдиреБрд░реЛрдзреЛрдВ рдХрд╛ рд╕рд╛рдордирд╛ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдЗрд╕ рдкреНрд░рдХрд╛рд░ рдХреА рд╕рдорд╕реНрдпрд╛рдУрдВ рд╕реЗ рдХреИрд╕реЗ рдЫреБрдЯрдХрд╛рд░рд╛ рдкрд╛рдПрдВ?

рдкреБрдирд░рд╛рд╡рд░реНрддреА рдкреНрд░рд╢реНрди рди рд▓рд┐рдЦреЗрдВ

рдФрд░ рдЧреИрд░-рдкреБрдирд░рд╛рд╡рд░реНрддреА рд▓рд┐рдЦреЗрдВред рднрд╡рджреАрдп, рдЖрдкрдХрд╛ рдХреЗ.рдУ.

рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ, PostgreSQL рдХрд╛рдлреА рдХрд╛рд░реНрдпрдХреНрд╖рдорддрд╛ рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИ рдЬрд┐рд╕рдХрд╛ рдЖрдк рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдирд╣реАрдВ рдкреНрд░рддреНрдпрд╛рд╡рд░реНрддрди рд▓рд╛рдЧреВ рдХрд░реЗрдВ.

рд╕рдорд╕реНрдпрд╛ рдХреЗ рдкреНрд░рддрд┐ рдореМрд▓рд┐рдХ рд░реВрдк рд╕реЗ рднрд┐рдиреНрди рджреГрд╖реНрдЯрд┐рдХреЛрдг рдХрд╛ рдкреНрд░рдпреЛрдЧ рдХрд░реЗрдВ

рдХрднреА-рдХрднреА рдЖрдк рд╕рдорд╕реНрдпрд╛ рдХреЛ рдХреЗрд╡рд▓ "рдЕрд▓рдЧ рдкрдХреНрд╖" рд╕реЗ рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВред рдореИрдВрдиреЗ рд▓реЗрдЦ рдореЗрдВ рдРрд╕реА рд╕реНрдерд┐рддрд┐ рдХрд╛ рдПрдХ рдЙрджрд╛рд╣рд░рдг рджрд┐рдпрд╛ рд╣реИ "рдПрд╕рдХреНрдпреВрдПрд▓ рд╣рд╛рдЙрдЯреЛ: 1000 рдФрд░ рдПрдХрддреНрд░реАрдХрд░рдг рдХрд╛ рдПрдХ рддрд░реАрдХрд╛" - рдХрд╕реНрдЯрдо рдПрдЧреНрд░реАрдЧреЗрдЯ рдлрд╝рдВрдХреНрд╢рдВрд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдП рдмрд┐рдирд╛ рд╕рдВрдЦреНрдпрд╛рдУрдВ рдХреЗ рдПрдХ рд╕реЗрдЯ рдХрд╛ рдЧреБрдгрди:

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;

рд▓реВрдк рдХреЗ рдмрдЬрд╛рдп 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);

PostgreSQL рдПрдВрдЯреАрдкреИрдЯрд░реНрди: "рдЕрдирдВрдд рд╕реАрдорд╛ рдирд╣реАрдВ рд╣реИ!", рдпрд╛ рд░рд┐рдХрд░реНрд╕рди рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдереЛрдбрд╝рд╛ рд╕рд╛
рдЦреИрд░, рдПрдХ рд╡рд┐рд╖рдп рдкрд░ рд╕рднреА рд╕рдВрджреЗрд╢реЛрдВ рдХреЛ рдбрд╛рдЙрдирд▓реЛрдб рдХрд░рдиреЗ рдХрд╛ рдПрдХ рд╕рд╛рдорд╛рдиреНрдп рдЕрдиреБрд░реЛрдз рдХреБрдЫ рдЗрд╕ рддрд░рд╣ рджрд┐рдЦрддрд╛ рд╣реИ:

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();

PostgreSQL рдПрдВрдЯреАрдкреИрдЯрд░реНрди: "рдЕрдирдВрдд рд╕реАрдорд╛ рдирд╣реАрдВ рд╣реИ!", рдпрд╛ рд░рд┐рдХрд░реНрд╕рди рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдереЛрдбрд╝рд╛ рд╕рд╛
рдЕрдм рд╣рдорд╛рд░реА рд╕рдВрдкреВрд░реНрдг рдкреБрдирд░рд╛рд╡рд░реНрддреА рдХреНрд╡реЗрд░реА рдХреЛ рдХреЗрд╡рд▓ рдЗрд╕ рддрдХ рд╕реАрдорд┐рдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ:

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 рдкрд░ред рдФрд░ рдХрд┐рд╕реА рдиреЗ рднреА "рдЪреМрдбрд╝рд╛рдИ" рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдХреБрдЫ рднреА рд╡рд╛рджрд╛ рдирд╣реАрдВ рдХрд┐рдпрд╛ред

рдФрдкрдЪрд╛рд░рд┐рдХ рд░реВрдк рд╕реЗ, рдРрд╕реА рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ рдЕрдирдВрдд рдирд╣реАрдВ рд╣реЛрдЧреА, рд▓реЗрдХрд┐рди рдпрджрд┐ рдкреНрд░рддреНрдпреЗрдХ рдЪрд░рдг рдкрд░ рд░рд┐рдХреЙрд░реНрдб рдХреА рд╕рдВрдЦреНрдпрд╛ рддреЗрдЬреА рд╕реЗ рдмрдврд╝рддреА рд╣реИ, рддреЛ рд╣рдо рд╕рднреА рдЕрдЪреНрдЫреА рддрд░рд╣ рд╕реЗ рдЬрд╛рдирддреЗ рд╣реИрдВ рдХрд┐ рдпрд╣ рдХреИрд╕реЗ рд╕рдорд╛рдкреНрдд рд╣реЛрддрд╛ рд╣реИ...

PostgreSQL рдПрдВрдЯреАрдкреИрдЯрд░реНрди: "рдЕрдирдВрдд рд╕реАрдорд╛ рдирд╣реАрдВ рд╣реИ!", рдпрд╛ рд░рд┐рдХрд░реНрд╕рди рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдереЛрдбрд╝рд╛ рд╕рд╛рджреЗрдЦреЗрдВ "рд╢рддрд░рдВрдЬ рдХреА рдмрд┐рд╕рд╛рдд рдкрд░ рдЕрдирд╛рдЬ рдХреА рд╕рдорд╕реНрдпрд╛"

"рдкрде" рдХреЗ рд╕рдВрд░рдХреНрд╖рдХ

рд╣рдо рдмрд╛рд░реА-рдмрд╛рд░реА рд╕реЗ рд░рд┐рдХрд░реНрд╕рди рдкрде рдХреЗ рд╕рд╛рде рдЖрдП рд╕рднреА рдСрдмреНрдЬреЗрдХреНрдЯ рдкрд╣рдЪрд╛рдирдХрд░реНрддрд╛рдУрдВ рдХреЛ рдПрдХ рд╕рд░рдгреА рдореЗрдВ рдЬреЛрдбрд╝рддреЗ рд╣реИрдВ, рдЬреЛ рдЗрд╕рдХреЗ рд▓рд┐рдП рдПрдХ рдЕрджреНрд╡рд┐рддреАрдп "рдкрде" рд╣реИ:

WITH RECURSIVE T AS (
  SELECT
    ARRAY[id] path
  ...
UNION ALL
  SELECT
    path || id
  ...
  WHERE
    id <> ALL(T.path) -- ╨╜╨╡ ╤Б╨╛╨▓╨┐╨░╨┤╨░╨╡╤В ╨╜╨╕ ╤Б ╨╛╨┤╨╜╨╕╨╝ ╨╕╨╖
)

рдкреНрд░реЛ: рдпрджрд┐ рдбреЗрдЯрд╛ рдореЗрдВ рдХреЛрдИ рдЪрдХреНрд░ рд╣реИ, рддреЛ рд╣рдо рдПрдХ рд╣реА рд░рд┐рдХреЙрд░реНрдб рдХреЛ рдПрдХ рд╣реА рдкрде рдореЗрдВ рдмрд╛рд░-рдмрд╛рд░ рд╕рдВрд╕рд╛рдзрд┐рдд рдирд╣реАрдВ рдХрд░реЗрдВрдЧреЗред
рд╡рд┐рдкрдХреНрд╖: рд▓реЗрдХрд┐рди рд╕рд╛рде рд╣реА, рд╣рдо рдЦреБрдж рдХреЛ рджреЛрд╣рд░рд╛рдП рдмрд┐рдирд╛ рд╕рдЪрдореБрдЪ рд╕рднреА рд░рд┐рдХреЙрд░реНрдб рдХреЛ рдмрд╛рдпрдкрд╛рд╕ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред

PostgreSQL рдПрдВрдЯреАрдкреИрдЯрд░реНрди: "рдЕрдирдВрдд рд╕реАрдорд╛ рдирд╣реАрдВ рд╣реИ!", рдпрд╛ рд░рд┐рдХрд░реНрд╕рди рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдереЛрдбрд╝рд╛ рд╕рд╛рджреЗрдЦреЗрдВ "рдирд╛рдЗрдЯреНрд╕ рдореВрд╡ рдкреНрд░реЙрдмреНрд▓рдо"

рдкрде рдХреА рд▓рдВрдмрд╛рдИ рд╕реАрдорд╛

рдЕрд╕рдВрдЧрдд рдЧрд╣рд░рд╛рдИ рдкрд░ рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ "рднрдЯрдХрдиреЗ" рдХреА рд╕реНрдерд┐рддрд┐ рд╕реЗ рдмрдЪрдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо рдкрд┐рдЫрд▓реЗ рджреЛ рддрд░реАрдХреЛрдВ рдХреЛ рдЬреЛрдбрд╝ рд╕рдХрддреЗ рд╣реИрдВред рдпрд╛, рдпрджрд┐ рд╣рдо рдЕрдирд╛рд╡рд╢реНрдпрдХ рдлрд╝реАрд▓реНрдб рдХрд╛ рд╕рдорд░реНрдерди рдирд╣реАрдВ рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ, рддреЛ рдкрде рдХреА рд▓рдВрдмрд╛рдИ рдХреЗ рдЕрдиреБрдорд╛рди рдХреЗ рд╕рд╛рде рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ рдЬрд╛рд░реА рд░рдЦрдиреЗ рдХреА рд╢рд░реНрдд рдХреЛ рдкреВрд░рдХ рдХрд░реЗрдВ:

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

рдПрдХ рдЯрд┐рдкреНрдкрдгреА рдЬреЛрдбрд╝реЗрдВ