PostgreSQL เชเชจเซเชŸเชฟเชชเซ‡เชŸเชฐเซเชจ: โ€œเช…เชจเช‚เชค เช เชฎเชฐเซเชฏเชพเชฆเชพ เชจเชฅเซ€!โ€, เช…เชฅเชตเชพ เชชเซเชจเชฐเชพเชตเชฐเซเชคเชจ เชตเชฟเชถเซ‡ เชฅเซ‹เชกเซเช‚

เชชเซเชจเชฐเชพเชตเชฐเซเชคเชจ - เชœเซ‹ เชธเช‚เชฌเช‚เชงเชฟเชค เชกเซ‡เชŸเชพ เชชเชฐ เชธเชฎเชพเชจ "เชŠเช‚เชกเชพเชฃ" เช•เซเชฐเชฟเชฏเชพเช“ เช•เชฐเชตเชพเชฎเชพเช‚ เช†เชตเซ‡ เชคเซ‹ เช–เซ‚เชฌ เชœ เชถเช•เซเชคเชฟเชถเชพเชณเซ€ เช…เชจเซ‡ เช…เชจเซเช•เซ‚เชณ เชฎเชฟเช•เซ‡เชจเชฟเชเชฎ. เชชเชฐเช‚เชคเซ เช…เชจเชฟเชฏเช‚เชคเซเชฐเชฟเชค เชชเซเชจเชฐเชพเชตเซƒเชคเซเชคเชฟ เช เชเช• เช…เชจเชฟเชทเซเชŸ เช›เซ‡ เชœเซ‡ เชฌเช‚เชจเซ‡เชฎเชพเช‚เชฅเซ€ เชเช• เชคเชฐเชซ เชฆเซ‹เชฐเซ€ เชถเช•เซ‡ เช›เซ‡ เช…เชจเช‚เชค เช…เชฎเชฒ เชชเซเชฐเช•เซเชฐเชฟเชฏเชพ, เช…เชฅเชตเชพ (เชœเซ‡ เชตเชงเซ เชตเช–เชค เชฅเชพเชฏ เช›เซ‡). เชฌเชงเซ€ เช‰เชชเชฒเชฌเซเชง เชฎเซ‡เชฎเชฐเซ€ "เช–เชพเชตเซเช‚"..

PostgreSQL เชเชจเซเชŸเชฟเชชเซ‡เชŸเชฐเซเชจ: โ€œเช…เชจเช‚เชค เช เชฎเชฐเซเชฏเชพเชฆเชพ เชจเชฅเซ€!โ€, เช…เชฅเชตเชพ เชชเซเชจเชฐเชพเชตเชฐเซเชคเชจ เชตเชฟเชถเซ‡ เชฅเซ‹เชกเซเช‚
เช† เชธเช‚เชฆเชฐเซเชญเชฎเชพเช‚ DBMS เชธเชฎเชพเชจ เชธเชฟเชฆเซเชงเชพเช‚เชคเซ‹ เชชเชฐ เช•เชพเชฎ เช•เชฐเซ‡ เช›เซ‡ - "เชคเซ‡เช“เช เชฎเชจเซ‡ เช–เซ‹เชฆเชตเชพเชจเซเช‚ เช•เชนเซเชฏเซเช‚, เชคเซ‡เชฅเซ€ เชนเซเช‚ เช–เซ‹เชฆเซเช‚". เชคเชฎเชพเชฐเซ€ เชตเชฟเชจเช‚เชคเซ€ เชฎเชพเชคเซเชฐ เชชเชกเซ‹เชถเซ€ เชชเซเชฐเช•เซเชฐเชฟเชฏเชพเช“เชจเซ‡ เชงเซ€เชฎเซเช‚ เช•เชฐเซ€ เชถเช•เชคเซ€ เชจเชฅเซ€, เชธเชคเชค เชชเซเชฐเซ‹เชธเซ‡เชธเชฐ เชธเช‚เชธเชพเชงเชจเซ‹ เชฒเซ‡ เช›เซ‡, เชชเชฃ เชธเชฎเช—เซเชฐ เชกเซ‡เชŸเชพเชฌเซ‡เชเชจเซ‡ "เช›เซ‹เชกเซ‹" เช…เชจเซ‡ เชฌเชงเซ€ เช‰เชชเชฒเชฌเซเชง เชฎเซ‡เชฎเชฐเซ€เชจเซ‡ "เช–เชพเชˆ" เชชเชฃ เชถเช•เซ‡ เช›เซ‡. เชคเซ‡เชฅเซ€ เช…เชจเช‚เชค เชชเซเชจเชฐเชพเชตเชฐเซเชคเชจ เชธเชพเชฎเซ‡ เชฐเช•เซเชทเชฃ - เชตเชฟเช•เชพเชธเช•เชฐเซเชคเชพเชจเซ€ เชชเซ‹เชคเชพเชจเซ€ เชœเชตเชพเชฌเชฆเชพเชฐเซ€.

PostgreSQL เชฎเชพเช‚, เชฆเซเชตเชพเชฐเชพ เชชเซเชจเชฐเชพเชตเชฐเซเชคเชฟเชค เชชเซเชฐเชถเซเชจเซ‹เชจเซ‹ เช‰เชชเชฏเซ‹เช— เช•เชฐเชตเชพเชจเซ€ เช•เซเชทเชฎเชคเชพ WITH RECURSIVE เช†เชตเซƒเชคเซเชคเชฟ 8.4 เชจเชพ เช…เชจเชพเชฆเชฟเช•เชพเชณเชฎเชพเช‚ เชฆเซ‡เช–เชพเชฏเชพ เชนเชคเชพ, เชชเชฐเช‚เชคเซ เชคเชฎเซ‡ เชนเชœเซ€ เชชเชฃ เชธเช‚เชญเชตเชฟเชค เชฐเซ‚เชชเซ‡ เชธเช‚เชตเซ‡เชฆเชจเชถเซ€เชฒ "เชฐเช•เซเชทเชฃเชนเซ€เชจ" เชตเชฟเชจเช‚เชคเซ€เช“เชจเซ‹ เชจเชฟเชฏเชฎเชฟเชคเชชเชฃเซ‡ เชธเชพเชฎเชจเซ‹ เช•เชฐเซ€ เชถเช•เซ‹ เช›เซ‹. เชคเชฎเชพเชฐเซ€ เชœเชพเชคเชจเซ‡ เช† เชชเซเชฐเช•เชพเชฐเชจเซ€ เชธเชฎเชธเซเชฏเชพเช“เชฅเซ€ เช•เซ‡เชตเซ€ เชฐเซ€เชคเซ‡ เช›เซเชŸเช•เชพเชฐเซ‹ เชฎเซ‡เชณเชตเชตเซ‹?

เชชเซเชจเชฐเชพเชตเชฐเซเชคเชฟเชค เชชเซเชฐเชถเซเชจเซ‹ เชฒเช–เชถเซ‹ เชจเชนเซ€เช‚

เช…เชจเซ‡ เชจเซ‹เชจ-เชฐเชฟเช•เชฐเซเชธเชฟเชต เชฒเช–เซ‹. เช†เชชเชจเซ€, เชคเชฎเชพเชฐเชพ K.O.

เชนเช•เซ€เช•เชคเชฎเชพเช‚, PostgreSQL เช˜เชฃเซ€ เชฌเชงเซ€ เช•เชพเชฐเซเชฏเช•เซเชทเชฎเชคเชพ เชชเซเชฐเชฆเชพเชจ เช•เชฐเซ‡ เช›เซ‡ เชœเซ‡เชจเซ‹ เชคเชฎเซ‡ เช‰เชชเชฏเซ‹เช— เช•เชฐเซ€ เชถเช•เซ‹ เช›เซ‹ เชจเชฅเซ€ เชชเซเชจเชฐเชพเชตเชฐเซเชคเชจ เชฒเชพเช—เซ เช•เชฐเซ‹.

เชธเชฎเชธเซเชฏเชพ เชฎเชพเชŸเซ‡ เชฎเซ‚เชณเชญเซ‚เชค เชฐเซ€เชคเซ‡ เช…เชฒเช— เช…เชญเชฟเช—เชฎเชจเซ‹ เช‰เชชเชฏเซ‹เช— เช•เชฐเซ‹

เช•เซ‡เชŸเชฒเซ€เช•เชตเชพเชฐ เชคเชฎเซ‡ เชซเช•เซเชค "เช…เชฒเช— เชฌเชพเชœเซ" เชฅเซ€ เชธเชฎเชธเซเชฏเชพเชจเซ‡ เชœเซ‹เชˆ เชถเช•เซ‹ เช›เซ‹. เชฎเซ‡เช‚ เชฒเซ‡เช–เชฎเชพเช‚ เช†เชตเซ€ เชชเชฐเชฟเชธเซเชฅเชฟเชคเชฟเชจเซเช‚ เช‰เชฆเชพเชนเชฐเชฃ เช†เชชเซเชฏเซเช‚ "SQL เช•เซ‡เชตเซ€ เชฐเซ€เชคเซ‡: 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;

เชชเชฐเช‚เชคเซ เช•เชพเชฐเชฃ เช•เซ‡ เช†เชชเชฃเชจเซ‡ เชนเช‚เชฎเซ‡เชถเชพ เชฐเซ‚เชŸ เชธเช‚เชฆเซ‡เชถเชฎเชพเช‚เชฅเซ€ เชธเชฎเช—เซเชฐ เชตเชฟเชทเชฏเชจเซ€ เชœเชฐเซ‚เชฐ เชนเซ‹เชฏ เช›เซ‡, เชคเซ‹ เชชเช›เซ€ เช†เชชเชฃเซ‡ เช•เซ‡เชฎ เชจเชนเซ€เช‚ เชฆเชฐเซ‡เช• เชเชจเซเชŸเซเชฐเซ€เชฎเชพเช‚ เชคเซ‡เชจเซเช‚ ID เช‰เชฎเซ‡เชฐเซ‹ เช†เชชเซ‹เช†เชช?

-- ะดะพะฑะฐะฒะธะผ ะฟะพะปะต ั ะพะฑั‰ะธะผ ะธะดะตะฝั‚ะธั„ะธะบะฐั‚ะพั€ะพะผ ั‚ะตะผั‹ ะธ ะธะฝะดะตะบั ะฝะฐ ะฝะตะณะพ
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

เชเช• เชŸเชฟเชชเซเชชเชฃเซ€ เช‰เชฎเซ‡เชฐเซ‹