{"id":321781,"date":"2021-04-20T15:01:19","date_gmt":"2021-04-20T15:01:19","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=321781"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=321781","title":{"rendered":"SQL HowTo: \u0440\u0435\u0448\u0430\u0435\u043c \u0433\u043e\u043b\u043e\u0432\u043e\u043b\u043e\u043c\u043a\u0443 \u00ab\u041d\u0435\u0431\u043e\u0441\u043a\u0440\u0451\u0431\u044b\u00bb \u043f\u043e\u0447\u0442\u0438 \u0431\u0435\u0437 \u043f\u0435\u0440\u0435\u0431\u043e\u0440\u0430"},"content":{"rendered":"\n<div class=\"post__text post__text_v2\" id=\"post-content-body\">\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/7e6\/b82\/788\/7e6b82788f133bb851c297838aacc6c3.png\" width=\"3327\" height=\"1453\"><figcaption><\/figcaption><\/figure>\n<p>\u041c\u043d\u043e\u0433\u0438\u0435 \u0437\u043d\u0430\u044e\u0442 \u043f\u0440\u0430\u0432\u0438\u043b\u0430 \u044d\u0442\u043e\u0439 \u0433\u043e\u043b\u043e\u0432\u043e\u043b\u043e\u043c\u043a\u0438 (<a href=\"http:\/\/www.playsudoku.ru\/skyscrapers.html\">Skyscrapers<\/a>):<\/p>\n<blockquote>\n<p>\u041f\u0435\u0440\u0435\u0434 \u0432\u0430\u043c\u0438 \u0432\u0438\u0434 \u0441\u0432\u0435\u0440\u0445\u0443 \u043d\u0430 \u0433\u043e\u0440\u043e\u0434\u0441\u043a\u043e\u0439 \u043a\u0432\u0430\u0440\u0442\u0430\u043b. \u0412 \u043a\u0430\u0436\u0434\u043e\u0439 \u043a\u043b\u0435\u0442\u043a\u0435 \u0441\u0442\u043e\u0438\u0442 &#171;\u043d\u0435\u0431\u043e\u0441\u043a\u0440\u0435\u0431&#187; \u0432\u044b\u0441\u043e\u0442\u043e\u0439, \u0440\u0430\u0432\u043d\u043e\u0439 \u0447\u0438\u0441\u043b\u0443 \u0432 \u044d\u0442\u043e\u0439 \u043a\u043b\u0435\u0442\u043a\u0435. \u0427\u0438\u0441\u043b\u0430 \u0441 \u0431\u043e\u043a\u043e\u0432 \u0441\u0435\u0442\u043a\u0438 \u043e\u0437\u043d\u0430\u0447\u0430\u044e\u0442 <strong>\u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e &#171;\u043d\u0435\u0431\u043e\u0441\u043a\u0440\u0435\u0431\u043e\u0432&#187;, \u0432\u0438\u0434\u0438\u043c\u044b\u0445<\/strong> \u0438\u0437 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0439 \u0441\u0442\u0440\u043e\u043a\u0438 \u0438\u043b\u0438 \u0441\u0442\u043e\u043b\u0431\u0446\u0430, \u0435\u0441\u043b\u0438 \u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043e\u0442 \u044d\u0442\u043e\u0433\u043e \u0447\u0438\u0441\u043b\u0430.<\/p>\n<p>\u0417\u0430\u0434\u0430\u0447\u0430: \u0437\u0430\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u0441\u0435\u0442\u043a\u0443 \u0447\u0438\u0441\u043b\u0430\u043c\u0438 \u0442\u0430\u043a, \u0447\u0442\u043e\u0431\u044b \u0432 \u043a\u0430\u0436\u0434\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0435 \u0438 \u0432 \u043a\u0430\u0436\u0434\u043e\u043c \u0441\u0442\u043e\u043b\u0431\u0446\u0435 <strong>\u043a\u0430\u0436\u0434\u043e\u0435 \u0447\u0438\u0441\u043b\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u043e\u0441\u044c \u043b\u0438\u0448\u044c \u0435\u0434\u0438\u043d\u043e\u0436\u0434\u044b<\/strong>.<\/p>\n<\/blockquote>\n<p>\u041f\u043e\u043d\u044f\u0442\u043d\u043e, \u0447\u0442\u043e \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u043e\u043c \u043f\u043e\u043b\u043d\u043e\u0433\u043e \u043f\u0435\u0440\u0435\u0431\u043e\u0440\u0430 \u043c\u043e\u0436\u043d\u043e \u0440\u0435\u0448\u0438\u0442\u044c \u0447\u0442\u043e \u0443\u0433\u043e\u0434\u043d\u043e, \u043d\u043e &#8212; \u0437\u0430 \u044d\u043a\u0441\u043f\u043e\u043d\u0435\u043d\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u0435 \u0432\u0440\u0435\u043c\u044f. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043c\u044b \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u043c \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0442\u0430\u043a\u043e\u0439 SQL-\u0437\u0430\u043f\u0440\u043e\u0441, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0440\u0435\u0448\u0438\u0442 \u043d\u0430\u043c \u0442\u0430\u043a\u0443\u044e \u0433\u043e\u043b\u043e\u0432\u043e\u043b\u043e\u043c\u043a\u0443 \u0437\u0430 \u043f\u0440\u0438\u0435\u043c\u043b\u0435\u043c\u043e\u0435 \u0432\u0440\u0435\u043c\u044f.<\/p>\n<p>\u0417\u0430\u0447\u0435\u043c \u0436\u0435 \u0434\u0435\u043b\u0430\u0442\u044c \u044d\u0442\u043e \u043d\u0430 SQL? \u041f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u043c\u043e\u0436\u0435\u043c! \u0410 \u0437\u0430\u043e\u0434\u043d\u043e \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u044d\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 <strong>\u043d\u0430\u0443\u0447\u0438\u0442\u044c\u0441\u044f \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u0438\u0440\u043e\u0432\u0430\u0442\u044c &#171;\u043e\u0447\u0435\u043d\u044c \u0441\u043b\u043e\u0436\u043d\u044b\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b&#187;<\/strong>, \u0447\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u0438\u0433\u043e\u0434\u0438\u0442\u044c\u0441\u044f \u0438 \u0432 \u043e\u0431\u044b\u0447\u043d\u043e\u0439 \u0440\u0430\u0431\u043e\u0442\u0435.<\/p>\n<h2>\u0412\u043e\u0437\u044c\u043c\u0435\u043c \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u0439 \u043f\u0440\u0438\u043c\u0435\u0440<\/h2>\n<p>\u041b\u044e\u0431\u043e\u0439 \u0445\u043e\u0442\u044c \u0441\u043a\u043e\u043b\u044c\u043a\u043e-\u0442\u043e \u0441\u043b\u043e\u0436\u043d\u044b\u0439 SQL-\u0437\u0430\u043f\u0440\u043e\u0441 \u043b\u0443\u0447\u0448\u0435 \u0432\u0441\u0435\u0433\u043e \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u043d\u0430 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u0435. \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0432\u043e\u0437\u044c\u043c\u0435\u043c \u0434\u043b\u044f \u043d\u0435\u0433\u043e \u0441 \u0441\u0430\u0439\u0442\u0430 <a href=\"http:\/\/www.playsudoku.ru\/\">playsudoku.ru<\/a> \u043e\u0434\u0438\u043d \u0438\u0437 &#171;\u0441\u043b\u043e\u0436\u043d\u044b\u0445&#187; \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432 \u044d\u0442\u043e\u0439 \u0433\u043e\u043b\u043e\u0432\u043e\u043b\u043e\u043c\u043a\u0438 <a href=\"http:\/\/www.playsudoku.ru\/skyscrapers\/sky_9_3_01.html\">\u0432 \u0440\u0430\u0437\u043c\u0435\u0440\u0435 9&#215;9<\/a>:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/e29\/8e5\/28f\/e298e528fb9545034819f381572b4de6.png\" width=\"588\" height=\"620\"><figcaption><\/figcaption><\/figure>\n<details class=\"spoiler\">\n<summary>TL; DR &#8212; \u043d\u0435 \u0437\u0430\u0433\u043b\u044f\u0434\u044b\u0432\u0430\u0439\u0442\u0435 \u0431\u0435\u0437 \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0438!<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"sql\">WITH RECURSIVE src AS (   SELECT     x - 1 x   , y - 1 y   , nullif(n, '.')::integer n   FROM     (VALUES( -- http:\/\/www.playsudoku.ru\/skyscrapers\/sky_9_3_01.html $$ . 4 . 3 3 2 1 3 5 2 . . . 2 . . . . . . . 3 3 . . . . . . . . . 1 3 2 . 6 . 7 . 4 . . 3 2 . . 1 . . . 6 . 7 2 3 . . . 4 . 7 . . . 4 2 3 . 2 . . . 5 . . 2 1 . . 5 . 6 . 2 . 4 3 4 . . . . . . . . . . 4 . . . . . . . 7 . 3 . 3 3 2 3 4 6 1 2 5 . $$     )) T(s)   , LATERAL       regexp_split_to_table(regexp_replace(s, '(^\\n|\\n$)', '', 'g'), '\\n+')         WITH ORDINALITY AS L(line, y)   , LATERAL       regexp_split_to_table(line, '\\s+')         WITH ORDINALITY AS C(n, x) ) -- \u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c \"\u0431\u043e\u043a\u043e\u0432\u044b\u0435\" \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f , side AS (   SELECT     m - 1 m   , Y.*   FROM     (       SELECT         max(x) m       FROM         src     ) X   , LATERAL (       SELECT         array_agg(n ORDER BY x) FILTER(WHERE y = 0 AND x &gt; 0 AND x &lt; m) u       , array_agg(n ORDER BY x) FILTER(WHERE y = m AND x &gt; 0 AND x &lt; m) d       , array_agg(n ORDER BY y) FILTER(WHERE x = 0 AND y &gt; 0 AND y &lt; m) l       , array_agg(n ORDER BY y) FILTER(WHERE x = m AND y &gt; 0 AND y &lt; m) r       FROM         src     ) Y ) -- \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u043c \u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u044f , fix AS (   SELECT     x   , y   , array_agg(n) FILTER(       WHERE         coalesce( -- \u0437\u0430\u0449\u0438\u0442\u0430 \u043e\u0442 \u043d\u0435\u0437\u0430\u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0431\u043e\u043a\u043e\u0432\u043e\u0433\u043e \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f           NOT(             -- \u0435\u0434\u0438\u043d\u0438\u0447\u043a\u0430 \u043d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 =&gt; \u043c\u0430\u043a\u0441\u0438\u043c\u0443\u043c \u0432 \u0441\u043e\u0441\u0435\u0434\u043d\u0435\u0439 \u044f\u0447\u0435\u0439\u043a\u0435             (l[y] = 1 AND x = 1 AND n &lt; m) OR             (r[y] = 1 AND x = m AND n &lt; m) OR             (u[x] = 1 AND y = 1 AND n &lt; m) OR             (d[x] = 1 AND y = m AND n &lt; m) OR             -- \u0440\u0430\u0441\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0434\u043e \"\u0431\u043e\u0440\u0442\u0430\"             l[y] + n &gt; m + x OR             u[x] + n &gt; m + y OR             r[y] + n &gt; m + (m - x + 1) OR             d[x] + n &gt; m + (m - y + 1)           )         , TRUE         )     ) cell   FROM     side   , LATERAL       generate_series(1, m) x -- \"\u0446\u0438\u043a\u043b\" \u043f\u043e X   , LATERAL       generate_series(1, m) y -- \"\u0446\u0438\u043a\u043b\" \u043f\u043e Y   , LATERAL       generate_series(1, m) n -- \"\u0446\u0438\u043a\u043b\" \u043f\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f\u043c   GROUP BY     x, y ) , base AS (   SELECT     x   , y   , CASE       WHEN n IS NOT NULL THEN ARRAY[n] -- \u043f\u043e\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c \u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f       ELSE cell     END cell   FROM     fix   NATURAL LEFT JOIN     src   ORDER BY     x, y ) , rec_03 AS (   SELECT     '{}'::json[] fixpath   , json_agg(row_to_json(T)) matrix   , NULL::json result   , TRUE has_many   , FALSE has_none   FROM     base T UNION ALL   (     WITH mv AS (       TABLE rec_03     )     (       -- \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0435 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430 \"\u0432\u044b\u0447\u0435\u0440\u043a\u0438\u0432\u0430\u043d\u0438\u0439\"       SELECT         mv.fixpath       , mv.matrix       , T.result       , T.has_many       , T.has_none       FROM         mv       , LATERAL (           WITH RECURSIVE unpack AS (             SELECT               *             FROM               json_to_recordset(coalesce(result, matrix)) unpack(x bigint, y bigint, cell bigint[])           )           , rec_02 AS (             SELECT               0 lvl             , *             FROM               unpack           UNION ALL             -- \"\u0432\u044b\u0447\u0435\u0440\u043a\u0438\u0432\u0430\u043d\u0438\u0435\" \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439             (               WITH RECURSIVE mv AS (                 TABLE rec_02               )               , rec_01 AS (                 TABLE mv               UNION ALL                 (                   WITH mv AS (                     TABLE rec_01                   )                   , step0 AS (                     SELECT                       *                     , cell cell_new                     FROM                       mv                     WHERE                       NOT EXISTS(                         SELECT                           NULL                         FROM                           mv                         WHERE                           cell = '{}'                       )                   )                   -- \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0435 \u043f\u043e \u0441\u0442\u043e\u043b\u0431\u0446\u0443\/\u0441\u0442\u0440\u043e\u043a\u0435 \u043e\u0442 \u0437\u0430\u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439                   , heur_a AS (                     SELECT                       x                     , y                     , array_agg(DISTINCT cell_new[1]) cell_cross                     FROM                       step0                     WHERE                       array_length(cell, 1) = 1 -- \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0432 \u0442\u043e\u0447\u043a\u0435                     GROUP BY                       GROUPING SETS((x), (y))   -- \u0433\u0440\u0443\u043f\u043f\u0438\u0440\u0443\u0435\u043c \u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e \u0432 \u0434\u0432\u0443\u0445 \u0440\u0430\u0437\u0440\u0435\u0437\u0430\u0445                   )                   , step1 AS (                     SELECT                       lvl                     , s.x                     , s.y                     , cell                     , CASE                         -- \u0432\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u043c \u043d\u043e\u0432\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f \u043d\u0435\u0437\u0430\u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u044f\u0447\u0435\u0435\u043a                         WHEN array_length(cell_new, 1) &gt; 1 THEN                           ARRAY( -- \u0440\u0430\u0437\u043d\u043e\u0441\u0442\u044c \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432                             SELECT                               unnest(s.cell)                           EXCEPT                             SELECT                               unnest(hx.cell_cross)                           EXCEPT                             SELECT                               unnest(hy.cell_cross)                           )                         ELSE cell_new                       END cell_new                     FROM                       step0 s                     LEFT JOIN                       heur_a hx                         ON hx.x = s.x                     LEFT JOIN                       heur_a hy                         ON hy.y = s.y                   )                   -- \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u0430\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u0430\u044f \u043f\u043e\u0437\u0438\u0446\u0438\u044f \u0434\u043b\u044f \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f - \u043d\u0443\u0436\u043d\u0430\u044f                   , heur_b AS (                     SELECT DISTINCT                       s.x                     , s.y                     , ARRAY[n] cell_single                     FROM                       (                         SELECT                           *                         FROM                           step1                         WHERE                           array_length(cell_new, 1) &gt; 1                       ) s                     JOIN                       (                         SELECT                           x                         , y                         , unnest(cell_new) n                         FROM                           step1                         GROUP BY                           GROUPING SETS((n, x), (n, y)) -- \u0433\u0440\u0443\u043f\u043f\u0438\u0440\u0443\u0435\u043c \u043f\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044e \u0438 \u0441\u0442\u0440\u043e\u043a\u0435\/\u0441\u0442\u043e\u043b\u0431\u0446\u0443                         HAVING                           count(*) = 1 -- \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0441\u0442\u044c \u043f\u043e\u0437\u0438\u0446\u0438\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0432 \u0433\u0440\u0443\u043f\u043f\u0435                       ) T                         ON                           n = ANY(cell_new) AND                           (T.x = s.x OR T.y = s.y)                   )                   , step2 AS (                     SELECT                       lvl                     , x                     , y                     , cell                     , coalesce(cell_single, cell_new) cell_new                     FROM                       step1                     NATURAL LEFT JOIN                       heur_b                   )                   SELECT                     lvl + 1                   , x                   , y                   , cell_new cell                   FROM                     step2                   WHERE                     -- \u0438\u0442\u0435\u0440\u0438\u0440\u0443\u0435\u043c, \u043f\u043e\u043a\u0430 \u0445\u043e\u0442\u044c \u0447\u0442\u043e-\u0442\u043e \"\u0432\u044b\u0447\u0435\u0440\u043a\u0438\u0432\u0430\u0435\u0442\u0441\u044f\"                     EXISTS(                       SELECT                         NULL                       FROM                         step2                       WHERE                         array_length(cell_new, 1) &lt; array_length(cell, 1)                     )                 )               )               -- \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0439 \u0448\u0430\u0433 \u0440\u0435\u043a\u0443\u0440\u0441\u0438\u0438               , step3 AS (                 SELECT                   *                 FROM                   rec_01                 WHERE                   lvl = (SELECT max(lvl) FROM rec_01)               )               -- \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0435 \u0432\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u043f\u043e \u0441\u0442\u043e\u043b\u0431\u0446\u0430\u043c               , heur_cx AS (                 -- \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u043c \u0432\u0441\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u0435 \u043a\u043e\u043c\u0431\u0438\u043d\u0430\u0446\u0438\u0438 \u0431\u0435\u0437 \u043f\u043e\u0432\u0442\u043e\u0440\u043e\u0432                 WITH RECURSIVE gen AS (                   SELECT                     generate_series(1, m) x                   , 0::bigint y                   , '{}'::bigint[] comb                   FROM                     side                 UNION ALL                   SELECT                     s.x                   , s.y                   , comb || n                   FROM                     gen                   JOIN                     step3 s                       ON (s.x, s.y) = (gen.x, gen.y + 1)                   JOIN LATERAL                     unnest(cell) n                       ON n &lt;&gt; ALL(comb) -- \u0437\u0430\u043f\u0440\u0435\u0442 \u043f\u043e\u0432\u0442\u043e\u0440\u0430 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f                 )                 SELECT                   gen.x                 , ord.y                 , array_agg(DISTINCT n) cell_y                 FROM                   side                 JOIN                   gen                     ON array_length(comb, 1) = m -- \u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c \u0442\u043e\u043b\u044c\u043a\u043e \u0438\u0442\u043e\u0433\u043e\u0432\u044b\u0435 \u043a\u043e\u043c\u0431\u0438\u043d\u0430\u0446\u0438\u0438 \u043f\u043e\u043b\u043d\u043e\u0433\u043e \u0440\u0430\u0437\u043c\u0435\u0440\u0430                 JOIN LATERAL ( -- \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0435 \u043f\u043e \u043c\u0430\u0441\u0441\u0438\u0432\u0443 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \"\u0432\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u0438\"                     SELECT                       sum((comb[n] &gt; ALL(comb[:n-1]))::integer) vu                     , sum((comb[n] &gt; ALL(comb[n+1:]))::integer) vd                     FROM                       generate_series(1, m) n                   ) T                     ON (vu, vd) = (coalesce(u[x], vu), coalesce(d[x], vd)) -- \u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u044f\u0449\u0438\u0435                 , LATERAL                     unnest(comb)                       WITH ORDINALITY ord(n, y)                 GROUP BY                   1, 2               )               -- \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0435 \u0432\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u043f\u043e \u0441\u0442\u0440\u043e\u043a\u0430\u043c               , heur_cy AS (                 WITH RECURSIVE gen AS (                   SELECT                     0::bigint x                   , generate_series(1, m) y                   , '{}'::bigint[] comb                   FROM                     side                 UNION ALL                   SELECT                     s.x                   , s.y                   , comb || n                   FROM                     gen                   JOIN                     step3 s                       ON (s.x, s.y) = (gen.x + 1, gen.y)                   JOIN LATERAL                     unnest(cell) n                       ON n &lt;&gt; ALL(comb)                 )                 SELECT                   ord.x                 , gen.y                 , array_agg(DISTINCT n) cell_x                 FROM                   side                 JOIN                   gen                     ON array_length(comb, 1) = m                 JOIN LATERAL (                     SELECT                       sum((comb[n] &gt; ALL(comb[:n-1]))::integer) vl                     , sum((comb[n] &gt; ALL(comb[n+1:]))::integer) vr                     FROM                       generate_series(1, m) n                   ) T                     ON (vl, vr) = (coalesce(l[y], vl), coalesce(r[y], vr))                 , LATERAL                     unnest(comb)                       WITH ORDINALITY ord(n, x)                 GROUP BY                   1, 2               )               , step4 AS (                 SELECT                   lvl                 , x                 , y                 , cell                   -- \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0434\u043e\u043b\u0436\u043d\u044b \u0443\u0434\u043e\u0432\u043b\u0435\u0442\u0432\u043e\u0440\u044f\u0442\u044c \u0443\u0441\u043b\u043e\u0432\u0438\u044f\u043c \u0438 \u043f\u043e \u0441\u0442\u0440\u043e\u043a\u0435, \u0438 \u043f\u043e \u0441\u0442\u043e\u043b\u0431\u0446\u0443                 , ARRAY(                     SELECT                       unnest(cell)                   INTERSECT                     SELECT                       unnest(cell_x)                   INTERSECT                     SELECT                       unnest(cell_y)                   ) cell_new                 FROM                   step3                 NATURAL LEFT JOIN                   heur_cx                 NATURAL LEFT JOIN                   heur_cy               )               SELECT                 lvl + 1               , x               , y               , cell_new cell               FROM                 step4               WHERE                 EXISTS(                   SELECT                     NULL                   FROM                     step4 s                   JOIN                     mv                       USING(x, y)                   WHERE                     array_length(s.cell_new, 1) &lt; array_length(mv.cell, 1)                 )             )           )           , last_iter AS (             SELECT               x             , y             , cell             FROM               rec_02             WHERE               lvl = (SELECT max(lvl) FROM rec_02) AND               lvl &gt; 0           )           SELECT             coalesce(json_agg(row_to_json(T)), '[]') result           , bool_or(array_length(cell, 1) &gt; 1) has_many   -- \u0435\u0441\u0442\u044c \u044f\u0447\u0435\u0439\u043a\u0438 \u0441 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u043c\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f\u043c\u0438           , bool_or(coalesce(cell, '{}') = '{}') has_none -- \u0435\u0441\u0442\u044c \u043f\u0443\u0441\u0442\u044b\u0435 \u044f\u0447\u0435\u0439\u043a\u0438           FROM             last_iter T         ) T       WHERE         -- \u043d\u0435\u0447\u0435\u0442\u043d\u044b\u0439 \u0448\u0430\u0433         mv.result IS NULL     UNION ALL       -- \u0444\u0438\u043a\u0441\u0430\u0446\u0438\u044f \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \u044f\u0447\u0435\u0439\u043a\u0438       SELECT         T.fixpath       , T.matrix       , NULL       , mv.has_many       , mv.has_none       FROM         mv       , LATERAL (           WITH unpack AS (             SELECT               *             FROM               json_to_recordset(coalesce(result, matrix)) unpack(x bigint, y bigint, cell bigint[])           )           SELECT             -- \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0444\u0438\u043a\u0441\u0438\u0440\u0443\u0435\u043c\u0443\u044e \u044f\u0447\u0435\u0439\u043a\u0443 \u043a json[] \u0438 \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u0432 '[]'::json             to_json(matrix_flt || vn) matrix           , fixpath || vn fixpath           FROM             -- \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c \u0444\u0438\u043a\u0441\u0438\u0440\u0443\u0435\u043c\u0443\u044e \u044f\u0447\u0435\u0439\u043a\u0443             (               SELECT                 *               FROM                 unpack               WHERE                 array_length(cell, 1) &gt; 1               ORDER BY                 array_length(cell, 1), x, y               LIMIT 1             ) fix             -- \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u043c \u043e\u0442\u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 json \u0431\u0435\u0437 \u044d\u0442\u043e\u0439 \u044f\u0447\u0435\u0439\u043a\u0438           , LATERAL (               SELECT                 array_agg(row_to_json(T)) FILTER(WHERE (x, y) &lt;&gt; (fix.x, fix.y)) matrix_flt               FROM                 unpack T             ) T0             -- \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0443\u0435\u043c \u043f\u0435\u0440\u0435\u0431\u043e\u0440 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439           , LATERAL               unnest(cell) n             -- \u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c json-\u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u044d\u0442\u043e\u0439 \u044f\u0447\u0435\u0439\u043a\u0438 \u0441 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u043c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435\u043c           , LATERAL (               SELECT                 row_to_json(T) vn               FROM                 (                   SELECT                     x                   , y                   , ARRAY[n] cell                 ) T             ) T1         ) T       WHERE         -- \u0447\u0435\u0442\u043d\u044b\u0439 \u0448\u0430\u0433         mv.result IS NOT NULL AND         -- \u043f\u043e\u043a\u0430 \u043d\u0435\u0442 \u043f\u0443\u0441\u0442\u044b\u0445 \u044f\u0447\u0435\u0435\u043a, \u043d\u043e \u0435\u0441\u0442\u044c \u043d\u0435\u0437\u0430\u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435         mv.has_many AND         NOT mv.has_none     )   ) ) -- \u043d\u0430\u0445\u043e\u0434\u0438\u043c \u0438 \u0440\u0430\u0441\u043f\u0430\u043a\u043e\u0432\u044b\u0432\u0430\u0435\u043c \u0437\u0430\u043f\u0438\u0441\u044c \u0441 \u0440\u0435\u0448\u0435\u043d\u0438\u0435\u043c , unpack AS (   SELECT     *   FROM     json_to_recordset((       SELECT         result       FROM         rec_03       WHERE         NOT has_many AND -- \u043d\u0435\u0442 \u0432\u0430\u0440\u0438\u0430\u0442\u0438\u0432\u043d\u043e\u0441\u0442\u0438         NOT has_none     -- \u043d\u0435\u0442 \u0437\u0430\u043d\u0443\u043b\u0435\u043d\u0438\u0439       LIMIT 1     )) unpack(x bigint, y bigint, cell bigint[]) ) -- \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u043c \u0432 \u043c\u0430\u0442\u0440\u0438\u0446\u0443 SELECT   string_agg(     lpad(cell[1]::text, (SELECT length(m::text) FROM side))   , ' '   ORDER BY x   ) line FROM   unpack GROUP BY   y ORDER BY   y;<\/code><\/pre>\n<\/div>\n<\/details>\n<h4>\u0418\u0437 \u043f\u0441\u0435\u0432\u0434\u043e\u043c\u0430\u0442\u0440\u0438\u0446\u044b &#8212; \u0432 \u0440\u0435\u043a\u043e\u0440\u0434\u0441\u0435\u0442<\/h4>\n<p>\u041a\u0430\u043a \u044d\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0432 SQL? \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0434\u043e\u0433\u043e\u0432\u043e\u0440\u0438\u043c\u0441\u044f, \u0447\u0442\u043e \u043f\u0443\u0441\u0442\u0430\u044f \u043a\u043b\u0435\u0442\u043a\u0430 \u0443 \u043d\u0430\u0441 \u0431\u0443\u0434\u0435\u0442 \u043e\u0431\u043e\u0437\u043d\u0430\u0447\u0435\u043d\u0430 \u0442\u043e\u0447\u043a\u043e\u0439, \u0430 \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u043d\u0430\u044f &#8212; \u0441\u0442\u043e\u044f\u0449\u0438\u043c \u0432 \u043d\u0435\u0439 \u0447\u0438\u0441\u043b\u043e\u043c. \u0422\u043e\u0433\u0434\u0430 \u0432\u0441\u044e \u043c\u0430\u0442\u0440\u0438\u0446\u0443 \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043a\u0430\u043a \u0435\u0434\u0438\u043d\u043e\u0435 \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0438 \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u0442\u044c \u043d\u0430 \u0441\u0442\u0440\u043e\u043a\u0438-\u0441\u0442\u043e\u043b\u0431\u0446\u044b \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043f\u0430\u0440\u044b \u0440\u0435\u0433\u0443\u043b\u044f\u0440\u043d\u044b\u0445 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0439:<\/p>\n<pre><code class=\"sql\">WITH src AS (   SELECT     x - 1 x   , y - 1 y   , nullif(n, '.')::integer n   FROM     (VALUES( -- http:\/\/www.playsudoku.ru\/skyscrapers\/sky_9_3_01.html $$ . 4 . 3 3 2 1 3 5 2 . . . 2 . . . . . . . 3 3 . . . . . . . . . 1 3 2 . 6 . 7 . 4 . . 3 2 . . 1 . . . 6 . 7 2 3 . . . 4 . 7 . . . 4 2 3 . 2 . . . 5 . . 2 1 . . 5 . 6 . 2 . 4 3 4 . . . . . . . . . . 4 . . . . . . . 7 . 3 . 3 3 2 3 4 6 1 2 5 . $$     )) T(s)   , LATERAL       regexp_split_to_table(regexp_replace(s, '(^\\n|\\n$)', '', 'g'), '\\n+')         WITH ORDINALITY AS L(line, y)   , LATERAL       regexp_split_to_table(line, '\\s+')         WITH ORDINALITY AS C(n, x) )<\/code><\/pre>\n<p>\u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0443\u0436\u0435 \u043f\u0440\u043e\u043d\u0443\u043c\u0435\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0437\u0430 \u0441\u0447\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f <code>WITH ORDINALITY<\/code> \u0440\u0435\u043a\u043e\u0440\u0434\u0441\u0435\u0442 \u0438\u0437 11 x 11 \u0441\u0442\u0440\u043e\u043a &#8212; \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0439 \u043a\u0432\u0430\u0434\u0440\u0430\u0442 9 x 9, \u043f\u043b\u044e\u0441 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f &#171;\u0432\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u0438&#187; \u0441\u0432\u0435\u0440\u0445\u0443-\u0441\u043d\u0438\u0437\u0443 \u0438 \u0441\u043b\u0435\u0432\u0430-\u0441\u043f\u0440\u0430\u0432\u0430:<\/p>\n<pre><code> x | y | n  0 | 0 | -  1 | 0 | 4  2 | 0 | -  3 | 0 | 3  4 | 0 | 3  5 | 0 | 2  6 | 0 | 1  7 | 0 | 3  8 | 0 | 5  9 | 0 | 2 10 | 0 | -  0 | 1 | -  1 | 1 | -  2 | 1 | 2  ...<\/code><\/pre>\n<p>\u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043c\u044b &#171;\u0441\u0442\u0440\u043e\u0438\u043c&#187; \u0437\u0430\u0432\u0435\u0434\u043e\u043c\u043e \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0441\u043b\u043e\u0436\u043d\u044b\u0439 \u0437\u0430\u043f\u0440\u043e\u0441, \u0442\u043e <a href=\"https:\/\/postgrespro.ru\/docs\/postgresql\/13\/queries-with\">\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 CTE (Common Table Expression)<\/a> \u0432\u043c\u0435\u0441\u0442\u043e \u0432\u043b\u043e\u0436\u0435\u043d\u043d\u044b\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 &#8212; \u044d\u0442\u043e \u0438\u043c\u0435\u043d\u043d\u043e \u0442\u0430 &#171;\u0444\u0438\u0448\u043a\u0430&#187;, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0441\u0440\u0430\u0437\u0443 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0443\u043f\u0440\u043e\u0441\u0442\u0438\u0442\u044c \u0435\u0433\u043e &#171;\u0441\u0431\u043e\u0440\u043a\u0443&#187;.<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0438\u0437 \u044d\u0442\u043e\u0433\u043e \u0432\u044b\u0434\u0435\u043b\u0438\u043c <strong>\u043c\u0430\u0441\u0441\u0438\u0432\u044b<\/strong>, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0443\u0434\u0443\u0442 \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e &#171;\u0432\u0438\u0434\u0438\u043c\u044b\u0445 \u043d\u0435\u0431\u043e\u0441\u043a\u0440\u0435\u0431\u043e\u0432&#187; \u0432 \u043a\u0430\u0436\u0434\u043e\u0439 \u043f\u043e\u0437\u0438\u0446\u0438\u0438 \u043a\u0430\u0436\u0434\u043e\u0439 \u0438\u0437 4 \u0441\u0442\u043e\u0440\u043e\u043d \u043a\u0432\u0430\u0434\u0440\u0430\u0442\u0430:<\/p>\n<pre><code class=\"sql\">-- \u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c \"\u0431\u043e\u043a\u043e\u0432\u044b\u0435\" \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f , side AS (   SELECT     m - 1 m   , Y.*   FROM     (       SELECT         max(x) m       FROM         src     ) X   , LATERAL (       SELECT         array_agg(n ORDER BY x) FILTER(WHERE y = 0 AND x &gt; 0 AND x &lt; m) u       , array_agg(n ORDER BY x) FILTER(WHERE y = m AND x &gt; 0 AND x &lt; m) d       , array_agg(n ORDER BY y) FILTER(WHERE x = 0 AND y &gt; 0 AND y &lt; m) l       , array_agg(n ORDER BY y) FILTER(WHERE x = m AND y &gt; 0 AND y &lt; m) r       FROM         src     ) Y )<\/code><\/pre>\n<p>\u0411\u043e\u043d\u0443\u0441\u043e\u043c \u043c\u044b \u0432\u044b\u0447\u0438\u0441\u043b\u0438\u043b\u0438 <code>m<\/code> &#8212; \u0440\u0430\u0437\u043c\u0435\u0440 \u0441\u0442\u043e\u0440\u043e\u043d\u044b \u043d\u0430\u0448\u0435\u0433\u043e \u043a\u0432\u0430\u0434\u0440\u0430\u0442\u0430:<\/p>\n<pre><code>m | u                      | d                   | l                      | r 9 | {4,NULL,3,3,2,1,3,5,2} | {3,3,2,3,4,6,1,2,5} | {NULL,3,3,2,3,2,1,4,4} | {3,1,3,2,4,2,3,NULL,3}\"<\/code><\/pre>\n<p>\u0412 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043f\u043e\u0437\u0438\u0446\u0438\u044f\u0445 \u043e\u043a\u0430\u0437\u0430\u043b\u0441\u044f <code>NULL<\/code>, \u043d\u043e \u043d\u0430\u0441 \u044d\u0442\u043e \u043d\u0435 \u0434\u043e\u043b\u0436\u043d\u043e \u0441\u043c\u0443\u0449\u0430\u0442\u044c, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043c\u044b \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u0437\u043d\u0430\u0435\u043c \u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f\u0445 \u0432 \u044d\u0442\u0438\u0445 \u044f\u0447\u0435\u0439\u043a\u0430\u0445.<\/p>\n<h2>\u0411\u0430\u0437\u043e\u0432\u044b\u0435 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f<\/h2>\n<p>\u041f\u0435\u0440\u0432\u043e\u0435 \u0441\u043e\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e\u0435: \u0435\u0441\u043b\u0438 \u043d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 \u0441\u0442\u043e\u0438\u0442 <strong>\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 1<\/strong>, \u0442\u043e \u0432 \u0441\u043e\u0441\u0435\u0434\u043d\u0435\u0439 \u0441 \u043d\u0438\u043c \u044f\u0447\u0435\u0439\u043a\u0435 \u043c\u043e\u0436\u0435\u0442 \u0441\u0442\u043e\u044f\u0442\u044c <strong>\u0442\u043e\u043b\u044c\u043a\u043e \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0435 \u0438\u0437 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u0445 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439<\/strong>, \u0442\u043e \u0435\u0441\u0442\u044c <code>m<\/code>, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u0438\u043d\u0430\u0447\u0435 \u044d\u0442\u043e\u0442 &#171;\u0441\u0430\u043c\u044b\u0439 \u0432\u044b\u0441\u043e\u043a\u0438\u0439 \u043d\u0435\u0431\u043e\u0441\u043a\u0440\u0435\u0431&#187; \u0431\u0443\u0434\u0435\u0442 \u0432\u0441\u0435 \u0440\u0430\u0432\u043d\u043e &#171;\u043f\u0440\u043e\u0441\u0432\u0435\u0447\u0438\u0432\u0430\u0442\u044c&#187; \u0447\u0435\u0440\u0435\u0437 \u043b\u044e\u0431\u043e\u0439 \u0434\u0440\u0443\u0433\u043e\u0439 \u0438 \u043c\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0431\u0443\u0434\u0435\u043c &#171;\u0443\u0432\u0438\u0434\u0435\u0442\u044c&#187; \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043d\u0435 \u043c\u0435\u043d\u044c\u0448\u0435 2:<\/p>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/be2\/33d\/eaf\/be233deaf79619c9440c372bb7eb8e46.png\" alt=\"\u0415\u0441\u043b\u0438 \u0432\u0438\u0434\u043d\u043e \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u0438\u043d &quot;\u043d\u0435\u0431\u043e\u0441\u043a\u0440\u0435\u0431&quot;, \u0442\u043e \u0442\u043e\u043b\u044c\u043a\u043e \u0441\u0430\u043c\u044b\u0439 \u0432\u044b\u0441\u043e\u043a\u0438\u0439\" title=\"\u0415\u0441\u043b\u0438 \u0432\u0438\u0434\u043d\u043e \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u0438\u043d &quot;\u043d\u0435\u0431\u043e\u0441\u043a\u0440\u0435\u0431&quot;, \u0442\u043e \u0442\u043e\u043b\u044c\u043a\u043e \u0441\u0430\u043c\u044b\u0439 \u0432\u044b\u0441\u043e\u043a\u0438\u0439\" width=\"201\" height=\"116\"><figcaption>\u0415\u0441\u043b\u0438 \u0432\u0438\u0434\u043d\u043e \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u0438\u043d &#171;\u043d\u0435\u0431\u043e\u0441\u043a\u0440\u0435\u0431&#187;, \u0442\u043e \u0442\u043e\u043b\u044c\u043a\u043e \u0441\u0430\u043c\u044b\u0439 \u0432\u044b\u0441\u043e\u043a\u0438\u0439<\/figcaption><\/figure>\n<p>\u0412\u0442\u043e\u0440\u043e\u0435 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0435 \u0447\u0443\u0442\u044c \u0441\u043b\u043e\u0436\u043d\u0435\u0435. \u0420\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u043a\u0432\u0430\u0434\u0440\u0430\u0442\u0430 \u0441\u043e \u0441\u0442\u043e\u0440\u043e\u043d\u043e\u0439 4, \u043f\u0440\u0438 \u043a\u0430\u043a\u043e\u043c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0438 &#171;\u0441\u0431\u043e\u043a\u0443&#187;, \u043a\u0430\u043a\u0438\u0435 &#171;\u043d\u0435\u0431\u043e\u0441\u043a\u0440\u0435\u0431\u044b&#187; \u0433\u0434\u0435 \u0441\u0442\u043e\u044f\u0442\u044c \u0442\u043e\u0447\u043d\u043e \u043d\u0435 \u043c\u043e\u0433\u0443\u0442:<\/p>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/dae\/bda\/896\/daebda89683d326db465cd6cc5cd6d5e.png\" alt=\"\u0417\u0430\u043f\u0440\u0435\u0442 \u043f\u043e\u0437\u0438\u0446\u0438\u0439 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f &quot;\u0432\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u0438&quot;\" title=\"\u0417\u0430\u043f\u0440\u0435\u0442 \u043f\u043e\u0437\u0438\u0446\u0438\u0439 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f &quot;\u0432\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u0438&quot;\" width=\"507\" height=\"371\"><figcaption>\u0417\u0430\u043f\u0440\u0435\u0442 \u043f\u043e\u0437\u0438\u0446\u0438\u0439 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f &#171;\u0432\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u0438&#187;<\/figcaption><\/figure>\n<p>\u041e\u0447\u0435\u0432\u0438\u0434\u043d\u043e, \u0447\u0442\u043e \u0435\u0441\u043b\u0438 \u043c\u044b \u0432\u0438\u0434\u0438\u043c \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0435 \u0434\u043b\u044f \u0442\u0430\u043a\u043e\u0433\u043e \u043a\u0432\u0430\u0434\u0440\u0430\u0442\u0430 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 4, \u0442\u043e \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u0430\u044f \u0434\u043e\u043f\u0443\u0441\u0442\u0438\u043c\u0430\u044f \u043a\u043e\u043c\u0431\u0438\u043d\u0430\u0446\u0438\u044f: <code>1, 2, 3, 4<\/code>. \u0415\u0441\u043b\u0438 \u0436\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 3, \u0442\u043e \u043d\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u043d\u0438 \u043e\u0434\u043d\u043e\u0439 \u0440\u0430\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438, \u0433\u0434\u0435 \u0432 \u043f\u0435\u0440\u0432\u043e\u0439 \u043a\u043b\u0435\u0442\u043a\u0435 \u0441\u0442\u043e\u044f\u043b\u043e \u0431\u044b 3, \u0438\u043b\u0438 4 \u0432 \u043b\u044e\u0431\u043e\u0439 \u0438\u0437 \u043f\u0435\u0440\u0432\u044b\u0445 \u0434\u0432\u0443\u0445. \u0410\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u043e \u0434\u043b\u044f 2 \u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f 4 \u0432 \u043f\u0435\u0440\u0432\u043e\u0439 \u044f\u0447\u0435\u0439\u043a\u0435.<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0432\u044b\u0440\u0430\u0437\u0438\u043c \u044d\u0442\u043e \u043d\u0430 SQL:<\/p>\n<pre><code class=\"sql\">-- \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u043c \u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u044f , fix AS (   SELECT     x   , y   , array_agg(n) FILTER(       WHERE         coalesce( -- \u0437\u0430\u0449\u0438\u0442\u0430 \u043e\u0442 \u043d\u0435\u0437\u0430\u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0431\u043e\u043a\u043e\u0432\u043e\u0433\u043e \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f           NOT(             -- \u0435\u0434\u0438\u043d\u0438\u0447\u043a\u0430 \u043d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 =&gt; \u043c\u0430\u043a\u0441\u0438\u043c\u0443\u043c \u0432 \u0441\u043e\u0441\u0435\u0434\u043d\u0435\u0439 \u044f\u0447\u0435\u0439\u043a\u0435             (l[y] = 1 AND x = 1 AND n &lt; m) OR             (r[y] = 1 AND x = m AND n &lt; m) OR             (u[x] = 1 AND y = 1 AND n &lt; m) OR             (d[x] = 1 AND y = m AND n &lt; m) OR             -- \u0440\u0430\u0441\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0434\u043e \"\u0431\u043e\u0440\u0442\u0430\"             l[y] + n &gt; m + x OR             u[x] + n &gt; m + y OR             r[y] + n &gt; m + (m - x + 1) OR             d[x] + n &gt; m + (m - y + 1)           )         , TRUE         )     ) cell   FROM     side   , LATERAL       generate_series(1, m) x -- \"\u0446\u0438\u043a\u043b\" \u043f\u043e X   , LATERAL       generate_series(1, m) y -- \"\u0446\u0438\u043a\u043b\" \u043f\u043e Y   , LATERAL       generate_series(1, m) n -- \"\u0446\u0438\u043a\u043b\" \u043f\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f\u043c   GROUP BY     x, y )<\/code><\/pre>\n<p>\u0412 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435, \u043c\u044b \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043b\u0438 <strong>\u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0439 \u043a\u043b\u0435\u0442\u043a\u0438 \u043d\u0430\u0431\u043e\u0440 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439<\/strong>, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0442\u0430\u043c \u0432\u043e\u043e\u0431\u0449\u0435 \u043c\u043e\u0433\u0443\u0442 \u0441\u0442\u043e\u044f\u0442\u044c:<\/p>\n<pre><code>x | y | cell 1 | 1 | {1,2,3,4,5,6} 1 | 2 | {1,2,3,4,5,6,7} 1 | 3 | {1,2,3,4,5,6,7} 1 | 4 | {1,2,3,4,5,6,7,8} 1 | 5 | {1,2,3,4,5,6,7} 1 | 6 | {1,2,3,4,5,6,7,8} 1 | 7 | {9} 1 | 8 | {1,2,3,4,5,6} 1 | 9 | {1,2,3,4,5,6}<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043a \u044d\u0442\u043e\u043c\u0443 \u043c\u044b \u043b\u0435\u0433\u043a\u043e \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0438\u0441\u0445\u043e\u0434\u043d\u043e \u0438\u0437\u0432\u0435\u0441\u0442\u043d\u044b\u0435 \u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u043f\u043e\u0437\u0438\u0446\u0438\u0438 \u0438\u0437 \u0441\u0430\u043c\u043e\u0433\u043e \u043a\u0432\u0430\u0434\u0440\u0430\u0442\u0430, \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u0438\u0432 \u0438\u0445 \u0432 \u0432\u0438\u0434\u0435 \u043c\u0430\u0441\u0441\u0438\u0432\u0430 \u0438\u0437 \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0433\u043e \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0433\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f:<\/p>\n<pre><code class=\"sql\">, step0 AS (   SELECT     x   , y   , CASE       WHEN n IS NOT NULL THEN ARRAY[n] -- \u043f\u043e\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c \u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f       ELSE cell     END cell   FROM     fix   NATURAL LEFT JOIN     src   ORDER BY     x, y )<\/code><\/pre>\n<pre><code>x | y | cell 1 | 1 | {1,2,3,4,5,6} 1 | 2 | {1,2,3,4,5,6,7} 1 | 3 | {2} 1 | 4 | {1,2,3,4,5,6,7,8} 1 | 5 | {1,2,3,4,5,6,7} 1 | 6 | {3} 1 | 7 | {9} 1 | 8 | {1,2,3,4,5,6} 1 | 9 | {1,2,3,4,5,6}<\/code><\/pre>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/127\/eb7\/275\/127eb727568d71ece5de8f297802530b.png\" alt=\"\u041f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0431\u0430\u0437\u043e\u0432\u044b\u0445 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0439 \u043a \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u0439 \u043c\u0430\u0442\u0440\u0438\u0446\u0435\" title=\"\u041f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0431\u0430\u0437\u043e\u0432\u044b\u0445 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0439 \u043a \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u0439 \u043c\u0430\u0442\u0440\u0438\u0446\u0435\" width=\"1375\" height=\"1452\"><figcaption>\u041f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0431\u0430\u0437\u043e\u0432\u044b\u0445 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0439 \u043a \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u0439 \u043c\u0430\u0442\u0440\u0438\u0446\u0435<\/figcaption><\/figure>\n<p>\u042d\u0442\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0441\u0442\u0430\u043d\u0435\u0442 &#171;\u043d\u0443\u043b\u0435\u0432\u044b\u043c&#187; \u0448\u0430\u0433\u043e\u043c \u043d\u0430\u0448\u0435\u0433\u043e \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u0430.<\/p>\n<h2>\u042d\u0432\u0440\u0438\u0441\u0442\u0438\u043a\u0430 &#171;A&#187;: \u0445\u043e\u0434 \u043b\u0430\u0434\u044c\u0435\u0439<\/h2>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0432\u0441\u043f\u043e\u043c\u043d\u0438\u043c, \u0447\u0442\u043e \u043f\u043e \u0443\u0441\u043b\u043e\u0432\u0438\u044e \u0437\u0430\u0434\u0430\u0447\u0438, <strong>\u0432\u0441\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0432 \u043a\u0430\u0436\u0434\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0435 \u0438 \u043a\u0430\u0436\u0434\u043e\u043c \u0441\u0442\u043e\u043b\u0431\u0446\u0435 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b<\/strong>. \u042d\u0442\u043e \u0437\u043d\u0430\u0447\u0438\u0442, \u0447\u0442\u043e \u0435\u0441\u043b\u0438 \u043c\u044b \u0443\u0436\u0435 \u0434\u043e\u0441\u0442\u043e\u0432\u0435\u0440\u043d\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043b\u0438\u0441\u044c, \u0447\u0442\u043e \u0432 \u043a\u0430\u043a\u0438\u0445-\u0442\u043e \u043a\u043b\u0435\u0442\u043a\u0430\u0445 \u043d\u0430\u0445\u043e\u0434\u044f\u0442\u0441\u044f \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f, \u0442\u043e \u0438\u0445 \u043d\u0435 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0431\u043e\u043b\u044c\u0448\u0435 \u043d\u0438\u0433\u0434\u0435 \u0432 \u044d\u0442\u043e\u0439 \u0436\u0435 \u0441\u0442\u0440\u043e\u043a\u0435\/\u0441\u0442\u043e\u043b\u0431\u0446\u0435, \u0438 \u0438\u0445 \u043c\u043e\u0436\u043d\u043e &#171;\u0432\u044b\u0447\u0435\u0440\u043a\u043d\u0443\u0442\u044c&#187;.<\/p>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/8cc\/6af\/938\/8cc6af938ac80b3e83f8611638fc6dce.png\" alt=\"\u0417\u0430\u043f\u0440\u0435\u0442 \u043f\u043e\u0432\u0442\u043e\u0440\u0435\u043d\u0438\u044f \u0432 \u0441\u0442\u0440\u043e\u043a\u0435\/\u0441\u0442\u043e\u043b\u0431\u0446\u0435\" title=\"\u0417\u0430\u043f\u0440\u0435\u0442 \u043f\u043e\u0432\u0442\u043e\u0440\u0435\u043d\u0438\u044f \u0432 \u0441\u0442\u0440\u043e\u043a\u0435\/\u0441\u0442\u043e\u043b\u0431\u0446\u0435\" width=\"417\" height=\"417\"><figcaption>\u0417\u0430\u043f\u0440\u0435\u0442 \u043f\u043e\u0432\u0442\u043e\u0440\u0435\u043d\u0438\u044f \u0432 \u0441\u0442\u0440\u043e\u043a\u0435\/\u0441\u0442\u043e\u043b\u0431\u0446\u0435<\/figcaption><\/figure>\n<pre><code class=\"sql\">-- \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0435 \u043f\u043e \u0441\u0442\u043e\u043b\u0431\u0446\u0443\/\u0441\u0442\u0440\u043e\u043a\u0435 \u043e\u0442 \u0437\u0430\u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 , heur_a AS (   SELECT     x   , y   , array_agg(DISTINCT cell[1]) cell_cross   FROM     step0   WHERE     array_length(cell, 1) = 1 -- \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0432 \u0442\u043e\u0447\u043a\u0435   GROUP BY     GROUPING SETS((x), (y))   -- \u0433\u0440\u0443\u043f\u043f\u0438\u0440\u0443\u0435\u043c \u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e \u0432 \u0434\u0432\u0443\u0445 \u0440\u0430\u0437\u0440\u0435\u0437\u0430\u0445 )<\/code><\/pre>\n<pre><code>x | y | cell_cross 1 | - | {2,3,9} 2 | - | {2} 3 | - | {1,2,5,6} 4 | - | {4} 5 | - | {6,7} 6 | - | {7,9} 7 | - | {2,4,5,6,9} 8 | - | {7} 9 | - | {4,7,9} - | 1 | {2,9} - | 2 | {9} - | 3 | {2,4,6,7} - | 4 | {1,6,7} - | 5 | {4,7} - | 6 | {2,3,5} - | 7 | {2,4,5,6,9} - | 9 | {7,9}<\/code><\/pre>\n<pre><code class=\"sql\">, step1 AS (   SELECT     s.x   , s.y   , cell   , CASE       -- \u0432\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u043c \u043d\u043e\u0432\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f \u043d\u0435\u0437\u0430\u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u044f\u0447\u0435\u0435\u043a       WHEN array_length(cell, 1) &gt; 1 THEN         ARRAY( -- \u0440\u0430\u0437\u043d\u043e\u0441\u0442\u044c \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432           SELECT             unnest(s.cell)         EXCEPT           SELECT             unnest(hx.cell_cross)         EXCEPT           SELECT             unnest(hy.cell_cross)         )       ELSE cell     END cell_new   FROM     step0 s   LEFT JOIN     heur_a hx       ON hx.x = s.x   LEFT JOIN     heur_a hy       ON hy.y = s.y )<\/code><\/pre>\n<pre><code>x | y | cell              | cell_new 1 | 1 | {1,2,3,4,5,6}     | {4,6,1,5} 1 | 2 | {1,2,3,4,5,6,7}   | {4,6,7,1,5} 1 | 3 | {2}               | {2} 1 | 4 | {1,2,3,4,5,6,7,8} | {4,5,8} 1 | 5 | {1,2,3,4,5,6,7}   | {6,1,5} 1 | 6 | {3}               | {3} 1 | 7 | {9}               | {9} 1 | 8 | {1,2,3,4,5,6}     | {4,6,1,5} 1 | 9 | {1,2,3,4,5,6}     | {4,6,1,5} ...<\/code><\/pre>\n<p>\u0417\u0434\u0435\u0441\u044c \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0438 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0440\u0430\u0441\u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0435\u043d\u043d\u0443\u044e \u0432 PostgreSQL \u0442\u0435\u0445\u043d\u0438\u043a\u0443 \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u044f <strong>\u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0439 \u043d\u0430\u0434 \u043c\u0430\u0441\u0441\u0438\u0432\u0430\u043c\u0438 \u043a\u0430\u043a \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u0430\u043c\u0438<\/strong> \u0432 \u0441\u0438\u043b\u0443 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u044f \u0442\u0430\u043a\u0438\u0445 \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0445 \u0444\u0443\u043d\u043a\u0446\u0438\u0439:<\/p>\n<pre><code class=\"sql\">-- \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 arraySetA + arraySetB =   ARRAY(     SELECT unnest(arraySetA)   UNION     SELECT unnest(arraySetB)   ) -- \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 arraySetA - arraySetB = ARRAY(... EXCEPT ...) -- \u043f\u0435\u0440\u0435\u0441\u0435\u0447\u0435\u043d\u0438\u0435 arraySetA * arraySetB = ARRAY(... INTERSECT ...)<\/code><\/pre>\n<p>\u041f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c, \u0447\u0442\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/4ab\/890\/95b\/4ab89095bc7a3ddb545477942717c272.png\" alt=\"\u041f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0439 \u043f\u043e \u0441\u0442\u0440\u043e\u043a\u0435\/\u0441\u0442\u043e\u043b\u0431\u0446\u0443\" title=\"\u041f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0439 \u043f\u043e \u0441\u0442\u0440\u043e\u043a\u0435\/\u0441\u0442\u043e\u043b\u0431\u0446\u0443\" width=\"1375\" height=\"1452\"><figcaption>\u041f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0439 \u043f\u043e \u0441\u0442\u0440\u043e\u043a\u0435\/\u0441\u0442\u043e\u043b\u0431\u0446\u0443<\/figcaption><\/figure>\n<h2>\u042d\u0432\u0440\u0438\u0441\u0442\u0438\u043a\u0430 &#171;B&#187;: \u043e\u0434\u0438\u043d \u0432 \u043f\u043e\u043b\u0435 \u043d\u0435 \u0432\u043e\u0438\u043d<\/h2>\n<p>\u041e\u0431\u0440\u0430\u0442\u0438\u043c \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u043f\u0435\u0440\u0432\u0443\u044e \u0436\u0435 \u0441\u0442\u0440\u043e\u043a\u0443:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/c15\/ec5\/899\/c15ec5899f4aa04d759dae6c60771760.png\" width=\"908\" height=\"115\"><figcaption><\/figcaption><\/figure>\n<p>\u0418\u0437 \u0432\u0441\u0435\u0445 \u043e\u0441\u0442\u0430\u0432\u0448\u0438\u0445\u0441\u044f \u043a\u043e\u043c\u0431\u0438\u043d\u0430\u0446\u0438\u0439 <strong>\u043b\u0438\u0448\u044c \u0432 \u043e\u0434\u043d\u043e\u0439 \u043d\u0435\u0437\u0430\u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0439 \u044f\u0447\u0435\u0439\u043a\u0435 \u043c\u043e\u0436\u0435\u0442 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u044c\u0441\u044f \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435<\/strong> 8. \u0410, \u0440\u0430\u0437 \u043f\u043e \u0443\u0441\u043b\u043e\u0432\u0438\u044e \u0437\u0430\u0434\u0430\u0447\u0438, \u0432\u0441\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0432 \u0441\u0442\u0440\u043e\u043a\u0435\/\u0441\u0442\u043e\u043b\u0431\u0446\u0435 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b &#8212; \u0437\u043d\u0430\u0447\u0438\u0442, \u0438\u043c\u0435\u043d\u043d\u043e \u0442\u0430\u043c \u043e\u043d\u043e \u0438 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f.<\/p>\n<p>\u0412 \u043a\u043e\u0434\u0435 \u044d\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0442\u0430\u043a:<\/p>\n<pre><code class=\"sql\">-- \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u0430\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u0430\u044f \u043f\u043e\u0437\u0438\u0446\u0438\u044f \u0434\u043b\u044f \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f - \u043d\u0443\u0436\u043d\u0430\u044f , heur_b AS (   SELECT DISTINCT     s.x   , s.y   , ARRAY[n] cell_single   FROM     (       SELECT         *       FROM         step1       WHERE         array_length(cell_new, 1) &gt; 1     ) s   JOIN     (       SELECT         x       , y       , unnest(cell_new) n       FROM         step1       GROUP BY         GROUPING SETS((n, x), (n, y)) -- \u0433\u0440\u0443\u043f\u043f\u0438\u0440\u0443\u0435\u043c \u043f\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044e \u0438 \u0441\u0442\u0440\u043e\u043a\u0435\/\u0441\u0442\u043e\u043b\u0431\u0446\u0443       HAVING         count(*) = 1 -- \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0441\u0442\u044c \u043f\u043e\u0437\u0438\u0446\u0438\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0432 \u0433\u0440\u0443\u043f\u043f\u0435     ) T       ON         n = ANY(cell_new) AND         (T.x = s.x OR T.y = s.y) )<\/code><\/pre>\n<p>\u0417\u0430 \u043e\u0441\u043d\u043e\u0432\u0443 \u043c\u044b \u0431\u0435\u0440\u0435\u043c \u0443\u0436\u0435 \u043d\u0435 \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 <code>cell<\/code>, \u0430 <code>cell_new<\/code>, \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u043e\u0435 \u043d\u0430 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u043c \u0448\u0430\u0433\u0435 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u0430.<\/p>\n<pre><code>x | y | cell_single 1 | 2 | {7} 1 | 4 | {8} 3 | 5 | {9} 3 | 9 | {8} 4 | 3 | {9} 5 | 1 | {8} 8 | 8 | {9} 9 | 6 | {8}<\/code><\/pre>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/df0\/aba\/75a\/df0aba75a0a6bfada1d35a501e3d98fe.png\" alt=\"\u041e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0435 \u043f\u043e \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0439 \u043f\u043e\u0437\u0438\u0446\u0438\u0438\" title=\"\u041e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0435 \u043f\u043e \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0439 \u043f\u043e\u0437\u0438\u0446\u0438\u0438\" width=\"1375\" height=\"1452\"><figcaption>\u041e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0435 \u043f\u043e \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0439 \u043f\u043e\u0437\u0438\u0446\u0438\u0438<\/figcaption><\/figure>\n<pre><code class=\"sql\">, step2 AS (   SELECT     x   , y   , cell   , coalesce(cell_single, cell_new) cell_new   FROM     step1   NATURAL LEFT JOIN     heur_b )<\/code><\/pre>\n<p>\u041f\u043e\u0441\u043b\u0435 \u043d\u0430\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0439 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/146\/63b\/5c0\/14663b5c0dfa1ee0a747c4fa60a18e31.png\" alt=\"\u041f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0439 \u043f\u043e \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0439 \u043f\u043e\u0437\u0438\u0446\u0438\u0438\" title=\"\u041f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0439 \u043f\u043e \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0439 \u043f\u043e\u0437\u0438\u0446\u0438\u0438\" width=\"1375\" height=\"1452\"><figcaption>\u041f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0439 \u043f\u043e \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0439 \u043f\u043e\u0437\u0438\u0446\u0438\u0438<\/figcaption><\/figure>\n<h2>\u041e\u0440\u0433\u0430\u043d\u0438\u0437\u0443\u0435\u043c \u0440\u0435\u043a\u0443\u0440\u0441\u0438\u0432\u043d\u044b\u0435 \u0446\u0438\u043a\u043b\u044b<\/h2>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0441\u0430\u043c\u043e\u0435 \u0432\u0440\u0435\u043c\u044f \u0437\u0430\u043c\u0435\u0442\u0438\u0442\u044c, \u0447\u0442\u043e \u0447\u0430\u0441\u0442\u044c \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0445 \u043d\u0430 \u0432\u0442\u043e\u0440\u043e\u043c \u0448\u0430\u0433\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0441\u043d\u043e\u0432\u0430 &#171;\u0432\u044b\u0447\u0435\u0440\u043a\u043d\u0443\u0442\u044c&#187; \u0447\u0430\u0441\u0442\u044c \u043a\u043e\u043c\u0431\u0438\u043d\u0430\u0446\u0438\u0439 \u0442\u043e\u0447\u043d\u043e \u0442\u0430\u043a \u0436\u0435, \u043a\u0430\u043a \u043c\u044b \u0441\u0434\u0435\u043b\u0430\u043b\u0438 \u044d\u0442\u043e \u043d\u0430 \u043f\u0435\u0440\u0432\u043e\u043c \u0448\u0430\u0433\u0435 (\u0435\u0441\u043b\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0431\u044b\u043b\u043e \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u043c \u043f\u043e \u0441\u0442\u0440\u043e\u043a\u0435, \u0442\u043e \u0435\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u0443\u0431\u0440\u0430\u0442\u044c \u0438\u0437 \u0441\u0442\u043e\u043b\u0431\u0446\u0430 \u0438 \u043d\u0430\u043e\u0431\u043e\u0440\u043e\u0442), \u0430 \u043f\u043e\u0442\u043e\u043c \u043e\u043f\u044f\u0442\u044c \u043f\u043e\u0438\u0441\u043a\u0430\u0442\u044c &#171;\u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0435&#187;, \u0438 \u0441\u043d\u043e\u0432\u0430, \u0438 \u043e\u043f\u044f\u0442\u044c&#8230; &#8212; \u0442\u043e \u0435\u0441\u0442\u044c <strong>\u043d\u0430\u043c \u043d\u0443\u0436\u0435\u043d \u0446\u0438\u043a\u043b<\/strong>! \u0410 \u043d\u0430 SQL \u0446\u0438\u043a\u043b\u044b \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0443\u044e\u0442\u0441\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0440\u0435\u043a\u0443\u0440\u0441\u0438\u0432\u043d\u044b\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432.<\/p>\n<p>\u0421\u0430\u043c\u043e\u0435 \u0433\u043b\u0430\u0432\u043d\u043e\u0435 \u0432 \u0442\u0430\u043a\u0438\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u0430\u0445 &#8212; \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e \u043f\u043e\u0434\u043e\u0431\u0440\u0430\u0442\u044c \u0443\u0441\u043b\u043e\u0432\u0438\u0435 \u0432\u044b\u0445\u043e\u0434\u0430 \u0438\u0437 \u0440\u0435\u043a\u0443\u0440\u0441\u0438\u0438. \u041f\u043e\u0434\u0440\u043e\u0431\u043d\u043e \u044f \u043e\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u043b\u0441\u044f \u043d\u0430 \u044d\u0442\u043e\u0439 \u0442\u0435\u043c\u0435 \u0432 \u0441\u0442\u0430\u0442\u044c\u044f\u0445 <a href=\"https:\/\/habr.com\/ru\/post\/521344\/\">&#171;PostgreSQL Antipatterns: \u00ab\u0411\u0435\u0441\u043a\u043e\u043d\u0435\u0447\u043d\u043e\u0441\u0442\u044c \u2014 \u043d\u0435 \u043f\u0440\u0435\u0434\u0435\u043b!\u00bb, \u0438\u043b\u0438 \u041d\u0435\u043c\u043d\u043e\u0433\u043e \u043e \u0440\u0435\u043a\u0443\u0440\u0441\u0438\u0438&#187;<\/a> \u0438 <a href=\"https:\/\/habr.com\/ru\/post\/523812\/\">&#171;SQL HowTo: \u043b\u043e\u043c\u0430\u0435\u043c \u043c\u043e\u0437\u0433 \u043e\u0431 \u0434\u0435\u0440\u0435\u0432\u043e \u2014 \u0443\u043f\u043e\u0440\u044f\u0434\u043e\u0447\u0438\u0432\u0430\u0435\u043c \u0438\u0435\u0440\u0430\u0440\u0445\u0438\u044e \u0441 \u0440\u0435\u043a\u0443\u0440\u0441\u0438\u0435\u0439 \u0438 \u0431\u0435\u0437&#187;<\/a>.<\/p>\n<p>\u0414\u043b\u044f \u0434\u0430\u043d\u043d\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0438 \u043d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0442\u0435\u0445\u043d\u0438\u043a \u043d\u0443\u043c\u0435\u0440\u0430\u0446\u0438\u0438 \u0443\u0440\u043e\u0432\u043d\u044f \u0440\u0435\u043a\u0443\u0440\u0441\u0438\u0438 \u0438 &#171;\u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438&#187; \u0440\u0435\u043a\u0443\u0440\u0441\u0438\u0432\u043d\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u0432\u044b\u0431\u043e\u0440\u043a\u0438, \u0447\u0442\u043e\u0431\u044b \u043a \u043d\u0435\u0439 \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u043e\u0431\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f \u043d\u0435\u043e\u0434\u043d\u043e\u043a\u0440\u0430\u0442\u043d\u043e. \u041c\u043e\u0434\u0438\u0444\u0438\u0446\u0438\u0440\u0443\u0435\u043c \u043d\u0430\u0448 \u0437\u0430\u043f\u0440\u043e\u0441:<\/p>\n<pre><code class=\"sql\">WITH RECURSIVE src AS ( -- ... -- \u0432\u043c\u0435\u0441\u0442\u043e step0 , base AS (   SELECT     x   , y   , CASE       WHEN n IS NOT NULL THEN ARRAY[n] -- \u043f\u043e\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c \u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f       ELSE cell     END cell   FROM     fix   NATURAL LEFT JOIN     src   ORDER BY     x, y ) -- \u0440\u0435\u043a\u0443\u0440\u0441\u0438\u0432\u043d\u044b\u0439 \u0446\u0438\u043a\u043b , rec AS (   SELECT     0 lvl   , *   FROM     base UNION ALL   (     WITH step0 AS (       SELECT         *       , cell cell_new       FROM         rec     ) -- ... \u0432\u0441\u0435 \u0442\u0435 \u0436\u0435 heur_a, step1, heur_b, step2, \u0442\u043e\u043b\u044c\u043a\u043e \u0441 \"\u043f\u0440\u043e\u0442\u0430\u0441\u043a\u0438\u0432\u0430\u043d\u0438\u0435\u043c\" lvl     SELECT       lvl + 1     , x     , y     , cell_new cell     FROM       step2     WHERE       -- \u0438\u0442\u0435\u0440\u0438\u0440\u0443\u0435\u043c, \u043f\u043e\u043a\u0430 \u0445\u043e\u0442\u044c \u0447\u0442\u043e-\u0442\u043e \"\u0432\u044b\u0447\u0435\u0440\u043a\u0438\u0432\u0430\u0435\u0442\u0441\u044f\"       EXISTS(         SELECT           NULL         FROM           step2         WHERE           array_length(cell_new, 1) &lt; array_length(cell, 1)       )   ) )<\/code><\/pre>\n<details class=\"spoiler\">\n<summary>\u041f\u043e\u043b\u043d\u044b\u0439 \u0442\u0435\u043a\u0441\u0442 \u0437\u0430\u043f\u0440\u043e\u0441\u0430<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"sql\">WITH RECURSIVE src AS (   SELECT     x - 1 x   , y - 1 y   , nullif(n, '.')::integer n   FROM     (VALUES( -- http:\/\/www.playsudoku.ru\/skyscrapers\/sky_9_3_01.html $$ . 4 . 3 3 2 1 3 5 2 . . . 2 . . . . . . . 3 3 . . . . . . . . . 1 3 2 . 6 . 7 . 4 . . 3 2 . . 1 . . . 6 . 7 2 3 . . . 4 . 7 . . . 4 2 3 . 2 . . . 5 . . 2 1 . . 5 . 6 . 2 . 4 3 4 . . . . . . . . . . 4 . . . . . . . 7 . 3 . 3 3 2 3 4 6 1 2 5 . $$     )) T(s)   , LATERAL       regexp_split_to_table(regexp_replace(s, '(^\\n|\\n$)', '', 'g'), '\\n+')         WITH ORDINALITY AS L(line, y)   , LATERAL       regexp_split_to_table(line, '\\s+')         WITH ORDINALITY AS C(n, x) ) -- \u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c \"\u0431\u043e\u043a\u043e\u0432\u044b\u0435\" \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f , side AS (   SELECT     m - 1 m   , Y.*   FROM     (       SELECT         max(x) m       FROM         src     ) X   , LATERAL (       SELECT         array_agg(n ORDER BY x) FILTER(WHERE y = 0 AND x &gt; 0 AND x &lt; m) u       , array_agg(n ORDER BY x) FILTER(WHERE y = m AND x &gt; 0 AND x &lt; m) d       , array_agg(n ORDER BY y) FILTER(WHERE x = 0 AND y &gt; 0 AND y &lt; m) l       , array_agg(n ORDER BY y) FILTER(WHERE x = m AND y &gt; 0 AND y &lt; m) r       FROM         src     ) Y ) -- \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u043c \u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u044f , fix AS (   SELECT     x   , y   , array_agg(n) FILTER(       WHERE         coalesce( -- \u0437\u0430\u0449\u0438\u0442\u0430 \u043e\u0442 \u043d\u0435\u0437\u0430\u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0431\u043e\u043a\u043e\u0432\u043e\u0433\u043e \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f           NOT(             -- \u0435\u0434\u0438\u043d\u0438\u0447\u043a\u0430 \u043d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 =&gt; \u043c\u0430\u043a\u0441\u0438\u043c\u0443\u043c \u0432 \u0441\u043e\u0441\u0435\u0434\u043d\u0435\u0439 \u044f\u0447\u0435\u0439\u043a\u0435             (l[y] = 1 AND x = 1 AND n &lt; m) OR             (r[y] = 1 AND x = m AND n &lt; m) OR             (u[x] = 1 AND y = 1 AND n &lt; m) OR             (d[x] = 1 AND y = m AND n &lt; m) OR             -- \u0440\u0430\u0441\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0434\u043e \"\u0431\u043e\u0440\u0442\u0430\"             l[y] + n &gt; m + x OR             u[x] + n &gt; m + y OR             r[y] + n &gt; m + (m - x + 1) OR             d[x] + n &gt; m + (m - y + 1)           )         , TRUE         )     ) cell   FROM     side   , LATERAL       generate_series(1, m) x -- \"\u0446\u0438\u043a\u043b\" \u043f\u043e X   , LATERAL       generate_series(1, m) y -- \"\u0446\u0438\u043a\u043b\" \u043f\u043e Y   , LATERAL       generate_series(1, m) n -- \"\u0446\u0438\u043a\u043b\" \u043f\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f\u043c   GROUP BY     x, y ) , base AS (   SELECT     x   , y   , CASE       WHEN n IS NOT NULL THEN ARRAY[n] -- \u043f\u043e\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c \u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f       ELSE cell     END cell   FROM     fix   NATURAL LEFT JOIN     src   ORDER BY     x, y ) -- \u0440\u0435\u043a\u0443\u0440\u0441\u0438\u0432\u043d\u044b\u0439 \u0446\u0438\u043a\u043b , rec AS (   SELECT     0 lvl   , *   FROM     base UNION ALL   (     WITH step0 AS (       SELECT         *       , cell cell_new       FROM         rec     )     -- \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0435 \u043f\u043e \u0441\u0442\u043e\u043b\u0431\u0446\u0443\/\u0441\u0442\u0440\u043e\u043a\u0435 \u043e\u0442 \u0437\u0430\u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439     , heur_a AS (       SELECT         x       , y       , array_agg(DISTINCT cell_new[1]) cell_cross       FROM         step0       WHERE         array_length(cell, 1) = 1 -- \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0432 \u0442\u043e\u0447\u043a\u0435       GROUP BY         GROUPING SETS((x), (y))   -- \u0433\u0440\u0443\u043f\u043f\u0438\u0440\u0443\u0435\u043c \u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e \u0432 \u0434\u0432\u0443\u0445 \u0440\u0430\u0437\u0440\u0435\u0437\u0430\u0445     )     , step1 AS (       SELECT         lvl       , s.x       , s.y       , cell       , CASE           -- \u0432\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u043c \u043d\u043e\u0432\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f \u043d\u0435\u0437\u0430\u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u044f\u0447\u0435\u0435\u043a           WHEN array_length(cell_new, 1) &gt; 1 THEN             ARRAY( -- \u0440\u0430\u0437\u043d\u043e\u0441\u0442\u044c \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432               SELECT                 unnest(s.cell)             EXCEPT               SELECT                 unnest(hx.cell_cross)             EXCEPT               SELECT                 unnest(hy.cell_cross)             )           ELSE cell_new         END cell_new       FROM         step0 s       LEFT JOIN         heur_a hx           ON hx.x = s.x       LEFT JOIN         heur_a hy           ON hy.y = s.y     )     -- \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u0430\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u0430\u044f \u043f\u043e\u0437\u0438\u0446\u0438\u044f \u0434\u043b\u044f \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f - \u043d\u0443\u0436\u043d\u0430\u044f     , heur_b AS (       SELECT DISTINCT         s.x       , s.y       , ARRAY[n] cell_single       FROM         (           SELECT             *           FROM             step1           WHERE             array_length(cell_new, 1) &gt; 1         ) s       JOIN         (           SELECT             x           , y           , unnest(cell_new) n           FROM             step1           GROUP BY             GROUPING SETS((n, x), (n, y)) -- \u0433\u0440\u0443\u043f\u043f\u0438\u0440\u0443\u0435\u043c \u043f\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044e \u0438 \u0441\u0442\u0440\u043e\u043a\u0435\/\u0441\u0442\u043e\u043b\u0431\u0446\u0443           HAVING             count(*) = 1 -- \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0441\u0442\u044c \u043f\u043e\u0437\u0438\u0446\u0438\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0432 \u0433\u0440\u0443\u043f\u043f\u0435         ) T           ON             n = ANY(cell_new) AND             (T.x = s.x OR T.y = s.y)     )     , step2 AS (       SELECT         lvl       , x       , y       , cell       , coalesce(cell_single, cell_new) cell_new       FROM         step1       NATURAL LEFT JOIN         heur_b     )     SELECT       lvl + 1     , x     , y     , cell_new cell     FROM       step2     WHERE       -- \u0438\u0442\u0435\u0440\u0438\u0440\u0443\u0435\u043c, \u043f\u043e\u043a\u0430 \u0445\u043e\u0442\u044c \u0447\u0442\u043e-\u0442\u043e \"\u0432\u044b\u0447\u0435\u0440\u043a\u0438\u0432\u0430\u0435\u0442\u0441\u044f\"       EXISTS(         SELECT           NULL         FROM           step2         WHERE           array_length(cell_new, 1) &lt; array_length(cell, 1)       )   ) ) TABLE rec ORDER BY lvl DESC, x, y;<\/code><\/pre>\n<\/div>\n<\/details>\n<p>\u041f\u043e\u0441\u043b\u0435 3 \u0442\u0430\u043a\u0438\u0445 \u0438\u0442\u0435\u0440\u0430\u0446\u0438\u0439 &#171;\u0432\u044b\u0447\u0435\u0440\u043a\u0438\u0432\u0430\u043d\u0438\u044f&#187; \u043d\u0430\u0448\u0430 \u043c\u0430\u0442\u0440\u0438\u0446\u0430 \u043f\u0440\u0438\u043c\u0435\u0442 \u0442\u0430\u043a\u043e\u0439 \u0432\u0438\u0434:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/2da\/95b\/a9f\/2da95ba9f6494b8b875615f80d88e380.png\" alt=\"\u041f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0439 \u043f\u0435\u0440\u0435\u0441\u0435\u0447\u0435\u043d\u0438\u044f \u0438 \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0441\u0442\u0438 \u0432 \u0446\u0438\u043a\u043b\u0435\" title=\"\u041f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0439 \u043f\u0435\u0440\u0435\u0441\u0435\u0447\u0435\u043d\u0438\u044f \u0438 \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0441\u0442\u0438 \u0432 \u0446\u0438\u043a\u043b\u0435\" width=\"1375\" height=\"1452\"><figcaption>\u041f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0439 \u043f\u0435\u0440\u0435\u0441\u0435\u0447\u0435\u043d\u0438\u044f \u0438 \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0441\u0442\u0438 \u0432 \u0446\u0438\u043a\u043b\u0435<\/figcaption><\/figure>\n<p>\u041c\u043e\u0436\u043d\u043e \u0437\u0430\u043c\u0435\u0442\u0438\u0442\u044c, \u0447\u0442\u043e \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0443 \u043d\u0430\u0441 \u0437\u0430\u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043b\u043e\u0441\u044c \u0432 \u043f\u0440\u0435\u0434\u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u043c \u0441\u0442\u043e\u043b\u0431\u0446\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 8, \u043d\u043e \u0434\u0430\u043b\u044c\u0448\u0435 \u043c\u044b \u0443\u043f\u0435\u0440\u043b\u0438\u0441\u044c.<\/p>\n<h2>\u042d\u0432\u0440\u0438\u0441\u0442\u0438\u043a\u0430 &#171;C&#187;: \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0438 \u043f\u043e \u0441\u0442\u043e\u0440\u043e\u043d\u0430\u043c<\/h2>\n<p>\u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0432\u0437\u0433\u043b\u044f\u043d\u0435\u043c \u0432\u043d\u0438\u043c\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u043d\u0430 \u0442\u0440\u0435\u0442\u044c\u044e \u0441\u0442\u0440\u043e\u043a\u0443:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/d93\/a0a\/0bc\/d93a0a0bc580768ccff5e3e0cec674e5.png\" width=\"1173\" height=\"130\"><figcaption><\/figcaption><\/figure>\n<p>\u041f\u043e \u0443\u0441\u043b\u043e\u0432\u0438\u044e \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0441\u0442\u0438 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0432 \u0441\u0442\u0440\u043e\u043a\u0435, \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 <strong>\u043a\u043e\u043c\u0431\u0438\u043d\u0430\u0446\u0438\u0438 \u0440\u0430\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u043e\u043a \u0438 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0438\u0440\u0443\u044e\u0449\u0438\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f &#171;\u0432\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u0438&#187;<\/strong>:<\/p>\n<pre><code>3 | 2 1 6 9 7 8 4 3 5 | 3 + 3 | 2 1 6 9 7 8 4 5 3 | 4 - 3 | 2 8 6 9 7 1 4 3 5 | 3 + 3 | 2 8 6 9 7 1 4 5 3 | 4 - 3 | 2 8 6 9 7 3 4 1 5 | 3 + 3 | 2 8 6 9 7 3 4 5 1 | 4 - 3 | 2 8 6 9 7 5 4 1 3 | 5 - 3 | 2 8 6 9 7 5 4 3 1 | 6 -<\/code><\/pre>\n<p>\u041a\u0430\u043a \u0432\u0438\u0434\u0438\u043c, \u0434\u0430\u043b\u0435\u043a\u043e \u043d\u0435 \u0432\u0441\u0435 \u0440\u0430\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u0443\u0434\u043e\u0432\u043b\u0435\u0442\u0432\u043e\u0440\u044f\u044e\u0442 \u0438\u0437\u0432\u0435\u0441\u0442\u043d\u044b\u043c \u043d\u0430\u043c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f\u043c 3 \u0438 3. \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043e\u0441\u0442\u0430\u0432\u0438\u043c \u0442\u043e\u043b\u044c\u043a\u043e \u0442\u0435, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0434\u043e\u043f\u0443\u0441\u0442\u0438\u043c\u044b, \u0438 \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c, \u043d\u0430 \u043a\u0430\u043a\u0438\u0445 \u043f\u0435\u0440\u0435\u0431\u0438\u0440\u0430\u0435\u043c\u044b\u0445 \u043f\u043e\u0437\u0438\u0446\u0438\u044f\u0445 \u043a\u0430\u043a\u0438\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b:<\/p>\n<pre><code>  *       *   * * 2 1 6 9 7 8 4 3 5 2 8 6 9 7 1 4 3 5 2 8 6 9 7 3 4 1 5<\/code><\/pre>\n<p>\u041e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f, \u043d\u0430 \u043f\u0435\u0440\u0432\u043e\u0439 \u0442\u0430\u043a\u043e\u0439 \u043f\u043e\u0437\u0438\u0446\u0438\u0438 \u043c\u043e\u0433\u0443\u0442 \u0441\u0442\u043e\u044f\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e 1 \u0438 8, \u043d\u043e \u043d\u0438\u043a\u0430\u043a \u043d\u0435 3 \u0438 5, \u0430 \u043d\u0430 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0439 &#8212; \u043d\u0430\u043e\u0431\u043e\u0440\u043e\u0442, \u0442\u043e\u043b\u044c\u043a\u043e 5:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/8ab\/12d\/349\/8ab12d349d9aa926b6336f3bd32132a1.png\" alt=\"\u041e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0435 \u043f\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f\u043c &quot;\u0432\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u0438&quot;\" title=\"\u041e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0435 \u043f\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f\u043c &quot;\u0432\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u0438&quot;\" width=\"1174\" height=\"130\"><figcaption>\u041e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0435 \u043f\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f\u043c &#171;\u0432\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u0438&#187;<\/figcaption><\/figure>\n<p>\u041f\u0440\u043e\u0432\u0435\u0434\u044f \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u044b\u0439 \u0430\u043d\u0430\u043b\u0438\u0437 \u043f\u043e \u0432\u0441\u0435\u043c \u0441\u0442\u0440\u043e\u043a\u0430\u043c \u0438 \u0441\u0442\u043e\u043b\u0431\u0446\u0430\u043c \u043c\u044b \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0441\u043e\u043a\u0440\u0430\u0442\u0438\u043c \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u043e \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u0445 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439:<\/p>\n<pre><code class=\"sql\">-- \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0435 \u0432\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u043f\u043e \u0441\u0442\u043e\u043b\u0431\u0446\u0430\u043c , heur_cx AS (   -- \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u043c \u0432\u0441\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u0435 \u043a\u043e\u043c\u0431\u0438\u043d\u0430\u0446\u0438\u0438 \u0431\u0435\u0437 \u043f\u043e\u0432\u0442\u043e\u0440\u043e\u0432   WITH RECURSIVE gen AS (     SELECT       generate_series(1, m) x     , 0::bigint y     , '{}'::bigint[] comb     FROM       side   UNION ALL     SELECT       s.x     , s.y     , comb || n     FROM       gen     JOIN       step3 s         ON (s.x, s.y) = (gen.x, gen.y + 1)     JOIN LATERAL       unnest(cell) n         ON n &lt;&gt; ALL(comb) -- \u0437\u0430\u043f\u0440\u0435\u0442 \u043f\u043e\u0432\u0442\u043e\u0440\u0430 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f   )   SELECT     gen.x   , ord.y   , array_agg(DISTINCT n) cell_y   FROM     side   JOIN     gen       ON array_length(comb, 1) = m -- \u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c \u0442\u043e\u043b\u044c\u043a\u043e \u0438\u0442\u043e\u0433\u043e\u0432\u044b\u0435 \u043a\u043e\u043c\u0431\u0438\u043d\u0430\u0446\u0438\u0438 \u043f\u043e\u043b\u043d\u043e\u0433\u043e \u0440\u0430\u0437\u043c\u0435\u0440\u0430   JOIN LATERAL ( -- \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0435 \u043f\u043e \u043c\u0430\u0441\u0441\u0438\u0432\u0443 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \"\u0432\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u0438\"       SELECT         sum((comb[n] &gt; ALL(comb[:n-1]))::integer) vu       , sum((comb[n] &gt; ALL(comb[n+1:]))::integer) vd       FROM         generate_series(1, m) n     ) T       ON (vu, vd) = (coalesce(u[x], vu), coalesce(d[x], vd)) -- \u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u044f\u0449\u0438\u0435   , LATERAL       unnest(comb)         WITH ORDINALITY ord(n, y)   GROUP BY     1, 2 )<\/code><\/pre>\n<p>\u0410\u0431\u0441\u043e\u043b\u044e\u0442\u043d\u043e \u0441\u0438\u043c\u043c\u0435\u0442\u0440\u0438\u0447\u043d\u043e \u0442\u043e \u0436\u0435 \u0441\u0430\u043c\u043e\u0435 \u043f\u0440\u043e\u0434\u0435\u043b\u044b\u0432\u0430\u0435\u043c \u0434\u043b\u044f \u0441\u0442\u0440\u043e\u043a:<\/p>\n<pre><code class=\"sql\">-- \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0435 \u0432\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u043f\u043e \u0441\u0442\u0440\u043e\u043a\u0430\u043c , heur_cy AS (   WITH RECURSIVE gen AS (     SELECT       0::bigint x     , generate_series(1, m) y     , '{}'::bigint[] comb     FROM       side   UNION ALL     SELECT       s.x     , s.y     , comb || n     FROM       gen     JOIN       step3 s         ON (s.x, s.y) = (gen.x + 1, gen.y)     JOIN LATERAL       unnest(cell) n         ON n &lt;&gt; ALL(comb)   )   SELECT     ord.x   , gen.y   , array_agg(DISTINCT n) cell_x   FROM     side   JOIN     gen       ON array_length(comb, 1) = m   JOIN LATERAL (       SELECT         sum((comb[n] &gt; ALL(comb[:n-1]))::integer) vl       , sum((comb[n] &gt; ALL(comb[n+1:]))::integer) vr       FROM         generate_series(1, m) n     ) T       ON (vl, vr) = (coalesce(l[y], vl), coalesce(r[y], vr))   , LATERAL       unnest(comb)         WITH ORDINALITY ord(n, x)   GROUP BY     1, 2 )<\/code><\/pre>\n<pre><code class=\"sql\">, step4 AS (   SELECT     x   , y   , cell     -- \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0434\u043e\u043b\u0436\u043d\u044b \u0443\u0434\u043e\u0432\u043b\u0435\u0442\u0432\u043e\u0440\u044f\u0442\u044c \u0443\u0441\u043b\u043e\u0432\u0438\u044f\u043c \u0438 \u043f\u043e \u0441\u0442\u0440\u043e\u043a\u0435, \u0438 \u043f\u043e \u0441\u0442\u043e\u043b\u0431\u0446\u0443   , ARRAY(       SELECT         unnest(cell)     INTERSECT       SELECT         unnest(cell_x)     INTERSECT       SELECT         unnest(cell_y)     ) cell_new   FROM     step3   NATURAL LEFT JOIN     heur_cx   NATURAL LEFT JOIN     heur_cy )<\/code><\/pre>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/5c0\/626\/ac0\/5c0626ac0a744cce79d2a9696d44340d.png\" alt=\"\u041f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0439 \u043f\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f\u043c &quot;\u0432\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u0438&quot;\" title=\"\u041f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0439 \u043f\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f\u043c &quot;\u0432\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u0438&quot;\" width=\"1375\" height=\"1452\"><figcaption>\u041f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0439 \u043f\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f\u043c &#171;\u0432\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u0438&#187;<\/figcaption><\/figure>\n<p>\u041d\u0443, \u0430 \u0442\u0435\u043f\u0435\u0440\u044c \u0441\u043d\u043e\u0432\u0430 \u0445\u043e\u0447\u0435\u0442\u0441\u044f &#171;\u043f\u043e\u0432\u044b\u0447\u0435\u0440\u043a\u0438\u0432\u0430\u0442\u044c&#187; \u0438 \u043f\u043e\u0438\u0441\u043a\u0430\u0442\u044c \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0435&#8230;<\/p>\n<p>\u041c\u043e\u0436\u043d\u043e \u0431\u044b \u0438 \u0432 \u043f\u0435\u0440\u0432\u044b\u0439 \u0440\u0435\u043a\u0443\u0440\u0441\u0438\u0432\u043d\u044b\u0439 \u0431\u043b\u043e\u043a \u0432\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u044d\u0442\u043e\u0433\u043e \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f, \u043d\u043e \u0442\u043e\u0433\u0434\u0430 \u043e\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0442\u044c\u0441\u044f \u043d\u0430 \u043a\u0430\u0436\u0434\u043e\u043c \u0448\u0430\u0433\u0435 \u0440\u0435\u043a\u0443\u0440\u0441\u0438\u0438, \u0430 \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u043a\u043e\u0433\u0434\u0430 \u0443\u0436\u0435 \u0432\u0441\u0435 \u0432\u044b\u0447\u0435\u0440\u043a\u043d\u0443\u0442\u043e &#8212; \u0437\u043d\u0430\u0447\u0438\u0442, \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u043c\u044b\u0445 \u043a\u043e\u043c\u0431\u0438\u043d\u0430\u0446\u0438\u0439 \u0431\u0443\u0434\u0435\u0442 \u0435\u0449\u0435 \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u043c\u043d\u043e\u0433\u043e, \u0447\u0442\u043e \u043f\u0435\u0447\u0430\u043b\u044c\u043d\u043e \u0441\u043a\u0430\u0436\u0435\u0442\u0441\u044f \u043d\u0430 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u0430.<\/p>\n<p>\u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043f\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u043d\u043e\u0439 \u0432\u044b\u0448\u0435 \u043c\u0435\u0442\u043e\u0434\u0438\u043a\u0435 &#171;\u043e\u0431\u0440\u0435\u043a\u0443\u0440\u0441\u0438\u0432\u043b\u0438\u0432\u0430\u043d\u0438\u044f&#187; \u0437\u0430\u0432\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0435\u043c \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043e\u0434\u0438\u043d \u0432 \u0434\u0440\u0443\u0433\u043e\u0439:<\/p>\n<pre><code class=\"sql\">-- ... , rec_02 AS (   SELECT     0 lvl   , *   FROM     base UNION ALL   (     WITH RECURSIVE rec_01 AS (       SELECT         *       FROM         rec_02     UNION ALL       (         WITH step0 AS (           SELECT             *           , cell cell_new           FROM             rec_01         ) -- ...<\/code><\/pre>\n<details class=\"spoiler\">\n<summary>\u041f\u043e\u043b\u043d\u044b\u0439 \u0442\u0435\u043a\u0441\u0442 \u0437\u0430\u043f\u0440\u043e\u0441\u0430<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"sql\">WITH RECURSIVE src AS (   SELECT     x - 1 x   , y - 1 y   , nullif(n, '.')::integer n   FROM     (VALUES( -- http:\/\/www.playsudoku.ru\/skyscrapers\/sky_9_3_01.html $$ . 4 . 3 3 2 1 3 5 2 . . . 2 . . . . . . . 3 3 . . . . . . . . . 1 3 2 . 6 . 7 . 4 . . 3 2 . . 1 . . . 6 . 7 2 3 . . . 4 . 7 . . . 4 2 3 . 2 . . . 5 . . 2 1 . . 5 . 6 . 2 . 4 3 4 . . . . . . . . . . 4 . . . . . . . 7 . 3 . 3 3 2 3 4 6 1 2 5 . $$     )) T(s)   , LATERAL       regexp_split_to_table(regexp_replace(s, '(^\\n|\\n$)', '', 'g'), '\\n+')         WITH ORDINALITY AS L(line, y)   , LATERAL       regexp_split_to_table(line, '\\s+')         WITH ORDINALITY AS C(n, x) ) -- \u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c \"\u0431\u043e\u043a\u043e\u0432\u044b\u0435\" \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f , side AS (   SELECT     m - 1 m   , Y.*   FROM     (       SELECT         max(x) m       FROM         src     ) X   , LATERAL (       SELECT         array_agg(n ORDER BY x) FILTER(WHERE y = 0 AND x &gt; 0 AND x &lt; m) u       , array_agg(n ORDER BY x) FILTER(WHERE y = m AND x &gt; 0 AND x &lt; m) d       , array_agg(n ORDER BY y) FILTER(WHERE x = 0 AND y &gt; 0 AND y &lt; m) l       , array_agg(n ORDER BY y) FILTER(WHERE x = m AND y &gt; 0 AND y &lt; m) r       FROM         src     ) Y ) -- \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u043c \u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u044f , fix AS (   SELECT     x   , y   , array_agg(n) FILTER(       WHERE         coalesce( -- \u0437\u0430\u0449\u0438\u0442\u0430 \u043e\u0442 \u043d\u0435\u0437\u0430\u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0431\u043e\u043a\u043e\u0432\u043e\u0433\u043e \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f           NOT(             -- \u0435\u0434\u0438\u043d\u0438\u0447\u043a\u0430 \u043d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 =&gt; \u043c\u0430\u043a\u0441\u0438\u043c\u0443\u043c \u0432 \u0441\u043e\u0441\u0435\u0434\u043d\u0435\u0439 \u044f\u0447\u0435\u0439\u043a\u0435             (l[y] = 1 AND x = 1 AND n &lt; m) OR             (r[y] = 1 AND x = m AND n &lt; m) OR             (u[x] = 1 AND y = 1 AND n &lt; m) OR             (d[x] = 1 AND y = m AND n &lt; m) OR             -- \u0440\u0430\u0441\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0434\u043e \"\u0431\u043e\u0440\u0442\u0430\"             l[y] + n &gt; m + x OR             u[x] + n &gt; m + y OR             r[y] + n &gt; m + (m - x + 1) OR             d[x] + n &gt; m + (m - y + 1)           )         , TRUE         )     ) cell   FROM     side   , LATERAL       generate_series(1, m) x -- \"\u0446\u0438\u043a\u043b\" \u043f\u043e X   , LATERAL       generate_series(1, m) y -- \"\u0446\u0438\u043a\u043b\" \u043f\u043e Y   , LATERAL       generate_series(1, m) n -- \"\u0446\u0438\u043a\u043b\" \u043f\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f\u043c   GROUP BY     x, y ) , base AS (   SELECT     x   , y   , CASE       WHEN n IS NOT NULL THEN ARRAY[n] -- \u043f\u043e\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c \u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f       ELSE cell     END cell   FROM     fix   NATURAL LEFT JOIN     src   ORDER BY     x, y ) , rec_02 AS (   SELECT     0 lvl   , *   FROM     base UNION ALL   (     WITH RECURSIVE rec_01 AS (       SELECT         *       FROM         rec_02     UNION ALL       (         WITH step0 AS (           SELECT             *           , cell cell_new           FROM             rec_01         )         -- \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0435 \u043f\u043e \u0441\u0442\u043e\u043b\u0431\u0446\u0443\/\u0441\u0442\u0440\u043e\u043a\u0435 \u043e\u0442 \u0437\u0430\u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439         , heur_a AS (           SELECT             x           , y           , array_agg(DISTINCT cell_new[1]) cell_cross           FROM             step0           WHERE             array_length(cell, 1) = 1 -- \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0432 \u0442\u043e\u0447\u043a\u0435           GROUP BY             GROUPING SETS((x), (y))   -- \u0433\u0440\u0443\u043f\u043f\u0438\u0440\u0443\u0435\u043c \u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e \u0432 \u0434\u0432\u0443\u0445 \u0440\u0430\u0437\u0440\u0435\u0437\u0430\u0445         )         , step1 AS (           SELECT             lvl           , s.x           , s.y           , cell           , CASE               -- \u0432\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u043c \u043d\u043e\u0432\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f \u043d\u0435\u0437\u0430\u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u044f\u0447\u0435\u0435\u043a               WHEN array_length(cell_new, 1) &gt; 1 THEN                 ARRAY( -- \u0440\u0430\u0437\u043d\u043e\u0441\u0442\u044c \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432                   SELECT                     unnest(s.cell)                 EXCEPT                   SELECT                     unnest(hx.cell_cross)                 EXCEPT                   SELECT                     unnest(hy.cell_cross)                 )               ELSE cell_new             END cell_new           FROM             step0 s           LEFT JOIN             heur_a hx               ON hx.x = s.x           LEFT JOIN             heur_a hy               ON hy.y = s.y         )         -- \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u0430\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u0430\u044f \u043f\u043e\u0437\u0438\u0446\u0438\u044f \u0434\u043b\u044f \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f - \u043d\u0443\u0436\u043d\u0430\u044f         , heur_b AS (           SELECT DISTINCT             s.x           , s.y           , ARRAY[n] cell_single           FROM             (               SELECT                 *               FROM                 step1               WHERE                 array_length(cell_new, 1) &gt; 1             ) s           JOIN             (               SELECT                 x               , y               , unnest(cell_new) n               FROM                 step1               GROUP BY                 GROUPING SETS((n, x), (n, y)) -- \u0433\u0440\u0443\u043f\u043f\u0438\u0440\u0443\u0435\u043c \u043f\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044e \u0438 \u0441\u0442\u0440\u043e\u043a\u0435\/\u0441\u0442\u043e\u043b\u0431\u0446\u0443               HAVING                 count(*) = 1 -- \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0441\u0442\u044c \u043f\u043e\u0437\u0438\u0446\u0438\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0432 \u0433\u0440\u0443\u043f\u043f\u0435             ) T               ON                 n = ANY(cell_new) AND                 (T.x = s.x OR T.y = s.y)         )         , step2 AS (           SELECT             lvl           , x           , y           , cell           , coalesce(cell_single, cell_new) cell_new           FROM             step1           NATURAL LEFT JOIN             heur_b         )         SELECT           lvl + 1         , x         , y         , cell_new cell         FROM           step2         WHERE           -- \u0438\u0442\u0435\u0440\u0438\u0440\u0443\u0435\u043c, \u043f\u043e\u043a\u0430 \u0445\u043e\u0442\u044c \u0447\u0442\u043e-\u0442\u043e \"\u0432\u044b\u0447\u0435\u0440\u043a\u0438\u0432\u0430\u0435\u0442\u0441\u044f\"           EXISTS(             SELECT               NULL             FROM               step2             WHERE               array_length(cell_new, 1) &lt; array_length(cell, 1)           )       )     )     -- \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0439 \u0448\u0430\u0433 \u0440\u0435\u043a\u0443\u0440\u0441\u0438\u0438     , step3 AS (       SELECT         lvl       , x       , y       , cell       FROM         rec_01       WHERE         lvl = (SELECT max(lvl) FROM rec_01)     )     -- \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0435 \u0432\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u043f\u043e \u0441\u0442\u043e\u043b\u0431\u0446\u0430\u043c     , heur_cx AS (       -- \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u043c \u0432\u0441\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u0435 \u043a\u043e\u043c\u0431\u0438\u043d\u0430\u0446\u0438\u0438 \u0431\u0435\u0437 \u043f\u043e\u0432\u0442\u043e\u0440\u043e\u0432       WITH RECURSIVE gen AS (         SELECT           generate_series(1, m) x         , 0::bigint y         , '{}'::bigint[] comb         FROM           side       UNION ALL         SELECT           s.x         , s.y         , comb || n         FROM           gen         JOIN           step3 s             ON (s.x, s.y) = (gen.x, gen.y + 1)         JOIN LATERAL           unnest(cell) n             ON n &lt;&gt; ALL(comb) -- \u0437\u0430\u043f\u0440\u0435\u0442 \u043f\u043e\u0432\u0442\u043e\u0440\u0430 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f       )       SELECT         gen.x       , ord.y       , array_agg(DISTINCT n) cell_y       FROM         side       JOIN         gen           ON array_length(comb, 1) = m -- \u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c \u0442\u043e\u043b\u044c\u043a\u043e \u0438\u0442\u043e\u0433\u043e\u0432\u044b\u0435 \u043a\u043e\u043c\u0431\u0438\u043d\u0430\u0446\u0438\u0438 \u043f\u043e\u043b\u043d\u043e\u0433\u043e \u0440\u0430\u0437\u043c\u0435\u0440\u0430       JOIN LATERAL ( -- \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0435 \u043f\u043e \u043c\u0430\u0441\u0441\u0438\u0432\u0443 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \"\u0432\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u0438\"           SELECT             sum((comb[n] &gt; ALL(comb[:n-1]))::integer) vu           , sum((comb[n] &gt; ALL(comb[n+1:]))::integer) vd           FROM             generate_series(1, m) n         ) T           ON (vu, vd) = (coalesce(u[x], vu), coalesce(d[x], vd)) -- \u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u044f\u0449\u0438\u0435       , LATERAL           unnest(comb)             WITH ORDINALITY ord(n, y)       GROUP BY         1, 2     )     -- \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0435 \u0432\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u043f\u043e \u0441\u0442\u0440\u043e\u043a\u0430\u043c     , heur_cy AS (       WITH RECURSIVE gen AS (         SELECT           0::bigint x         , generate_series(1, m) y         , '{}'::bigint[] comb         FROM           side       UNION ALL         SELECT           s.x         , s.y         , comb || n         FROM           gen         JOIN           step3 s             ON (s.x, s.y) = (gen.x + 1, gen.y)         JOIN LATERAL           unnest(cell) n             ON n &lt;&gt; ALL(comb)       )       SELECT         ord.x       , gen.y       , array_agg(DISTINCT n) cell_x       FROM         side       JOIN         gen           ON array_length(comb, 1) = m       JOIN LATERAL (           SELECT             sum((comb[n] &gt; ALL(comb[:n-1]))::integer) vl           , sum((comb[n] &gt; ALL(comb[n+1:]))::integer) vr           FROM             generate_series(1, m) n         ) T           ON (vl, vr) = (coalesce(l[y], vl), coalesce(r[y], vr))       , LATERAL           unnest(comb)             WITH ORDINALITY ord(n, x)       GROUP BY         1, 2     )     , step4 AS (       SELECT         lvl       , x       , y       , cell         -- \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0434\u043e\u043b\u0436\u043d\u044b \u0443\u0434\u043e\u0432\u043b\u0435\u0442\u0432\u043e\u0440\u044f\u0442\u044c \u0443\u0441\u043b\u043e\u0432\u0438\u044f\u043c \u0438 \u043f\u043e \u0441\u0442\u0440\u043e\u043a\u0435, \u0438 \u043f\u043e \u0441\u0442\u043e\u043b\u0431\u0446\u0443       , ARRAY(           SELECT             unnest(cell)         INTERSECT           SELECT             unnest(cell_x)         INTERSECT           SELECT             unnest(cell_y)             order by 1         ) cell_new       FROM         step3       NATURAL LEFT JOIN         heur_cx       NATURAL LEFT JOIN         heur_cy     )     SELECT       lvl + 1     , x     , y     , cell_new cell     FROM       step4     WHERE       EXISTS(         SELECT           NULL         FROM           step4         WHERE           array_length(cell_new, 1) &lt; array_length(cell, 1)       )   ) ) TABLE rec_02 ORDER lvl DESC, x, y;<\/code><\/pre>\n<\/div>\n<\/details>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/268\/a9c\/b80\/268a9cb80ab17633d3c2158fa7a88ee5.png\" width=\"1375\" height=\"1452\"><figcaption><\/figcaption><\/figure>\n<h2>\u0414\u0430 \u0437\u0434\u0440\u0430\u0432\u0441\u0442\u0432\u0443\u0435\u0442 \u0431\u0440\u0443\u0442\u0444\u043e\u0440\u0441!<\/h2>\n<p>\u0412\u043e\u0442 \u043c\u044b \u0438 \u043f\u0440\u0438\u0448\u043b\u0438 \u043a \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u0438, \u043a\u043e\u0433\u0434\u0430 \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u0439 \u0448\u0430\u0433 &#8212; \u043f\u0440\u044f\u043c\u043e\u0435 \u043c\u043e\u0434\u0435\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0441 \u043f\u043e\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u043e\u0439 \u0443\u0441\u043b\u043e\u0432\u0438\u0439. \u0418 \u0442\u0430\u043a\u0438 \u0434\u0430, \u0432 \u0442\u0430\u043a\u0443\u044e \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u044e \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043f\u043e\u043f\u0430\u0441\u0442\u044c \u043d\u0435 \u0440\u0430\u0437, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 &#8212; \u0441\u043d\u043e\u0432\u0430 \u0440\u0435\u043a\u0443\u0440\u0441\u0438\u044f.<\/p>\n<p>\u0427\u0442\u043e\u0431\u044b \u043d\u0435 \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u043f\u0435\u0440\u0435\u0431\u0438\u0440\u0430\u0442\u044c \u043c\u043d\u043e\u0433\u043e, \u043d\u0430 \u043a\u0430\u0436\u0434\u043e\u043c \u0442\u0430\u043a\u043e\u043c \u0448\u0430\u0433\u0435 \u043c\u044b \u0432\u043e\u0437\u044c\u043c\u0435\u043c \u0441\u0430\u043c\u0443\u044e \u043f\u0435\u0440\u0432\u0443\u044e \u044f\u0447\u0435\u0439\u043a\u0443, \u0433\u0434\u0435 \u043c\u0435\u043d\u044c\u0448\u0435 \u0432\u0441\u0435\u0433\u043e \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439, \u0438 \u043f\u043e\u043e\u0447\u0435\u0440\u0435\u0434\u043d\u043e \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u043c \u043f\u043e\u0434\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043a\u0430\u0436\u0434\u043e\u0435 \u0438\u0437 \u043d\u0438\u0445.<\/p>\n<h4>json_to_recordset<\/h4>\n<p>\u041d\u043e \u043a\u0430\u043a \u043f\u0435\u0440\u0435\u0434\u0430\u0442\u044c \u0446\u0435\u043b\u0443\u044e \u043c\u0430\u0442\u0440\u0438\u0446\u0443 \u043c\u0435\u0436\u0434\u0443 \u0448\u0430\u0433\u0430\u043c\u0438 \u0440\u0435\u043a\u0443\u0440\u0441\u0438\u0438, \u0434\u0430 \u0435\u0449\u0435 \u0438 \u0441 \u043f\u043e\u0434\u043c\u0435\u043d\u043e\u0439 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0432 \u044f\u0447\u0435\u0439\u043a\u0435? \u0422\u0443\u0442 \u043d\u0430\u043c \u043f\u0440\u0438\u0434\u0443\u0442 \u043d\u0430 \u043f\u043e\u043c\u043e\u0449\u044c \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 \u043d\u0430\u0434 json:<\/p>\n<pre><code class=\"sql\">-- \"\u0443\u043f\u0430\u043a\u043e\u0432\u043a\u0430\" \u043c\u0430\u0442\u0440\u0438\u0446\u044b SELECT   json_agg(row_to_json(T)) result FROM   last_iter T<\/code><\/pre>\n<pre><code class=\"sql\">-- \"\u0440\u0430\u0441\u043f\u0430\u043a\u043e\u0432\u043a\u0430\" \u043c\u0430\u0442\u0440\u0438\u0446\u044b , unpack AS (   SELECT     *   FROM     json_to_recordset(result) unpack(x bigint, y bigint, cell bigint[]) )<\/code><\/pre>\n<p>\u0422\u043e\u0433\u0434\u0430 \u043d\u0430\u0448\u0430 &#171;\u043f\u0435\u0440\u0435\u0441\u0431\u043e\u0440\u043a\u0430&#187; \u043c\u0430\u0442\u0440\u0438\u0446\u044b \u0441 \u0444\u0438\u043a\u0441\u0430\u0446\u0438\u0435\u0439 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0432 \u044f\u0447\u0435\u0439\u043a\u0435 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0442\u0430\u043a:<\/p>\n<pre><code class=\"sql\">SELECT   -- \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0444\u0438\u043a\u0441\u0438\u0440\u0443\u0435\u043c\u0443\u044e \u044f\u0447\u0435\u0439\u043a\u0443 \u043a json[] \u0438 \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u0432 '[]'::json   to_json(matrix_flt || vn) matrix FROM   -- \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c \u0444\u0438\u043a\u0441\u0438\u0440\u0443\u0435\u043c\u0443\u044e \u044f\u0447\u0435\u0439\u043a\u0443   (     SELECT       *     FROM       unpack     WHERE       array_length(cell, 1) &gt; 1     ORDER BY       array_length(cell, 1), x, y     LIMIT 1   ) fix   -- \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u043c \u043e\u0442\u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 json \u0431\u0435\u0437 \u044d\u0442\u043e\u0439 \u044f\u0447\u0435\u0439\u043a\u0438 , LATERAL (     SELECT       array_agg(row_to_json(T)) FILTER(WHERE (x, y) &lt;&gt; (fix.x, fix.y)) matrix_flt     FROM       unpack T   ) T0   -- \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0443\u0435\u043c \u043f\u0435\u0440\u0435\u0431\u043e\u0440 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 , LATERAL     unnest(cell) n   -- \u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c json-\u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u044d\u0442\u043e\u0439 \u044f\u0447\u0435\u0439\u043a\u0438 \u0441 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u043c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435\u043c , LATERAL (     SELECT       row_to_json(T) vn     FROM       (         SELECT           x         , y         , ARRAY[n] cell       ) T   ) T1<\/code><\/pre>\n<p>\u041f\u0440\u0438\u0447\u0435\u043c, \u043d\u0430\u0448\u0430 \u0440\u0435\u043a\u0443\u0440\u0441\u0438\u044f \u0434\u043e\u043b\u0436\u043d\u0430 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c &#171;\u0432 \u0434\u0432\u0430 \u0445\u043e\u0434\u0430&#187; &#8212; \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u0432\u044b\u0447\u0438\u0441\u043b\u044f\u044f \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043f\u043e \u0443\u0436\u0435 \u0437\u0430\u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u043c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f\u043c, \u0430 \u043f\u043e\u0442\u043e\u043c \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u044e \u043f\u043e\u0434\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u0434\u043b\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0433\u043e \u0448\u0430\u0433\u0430, \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u043a\u0430\u043a \u0432 \u0441\u0442\u0430\u0442\u044c\u0435 <a href=\"https:\/\/habr.com\/ru\/post\/486072\/\">&#171;SQL HowTo: \u043f\u0438\u0448\u0435\u043c while-\u0446\u0438\u043a\u043b \u043f\u0440\u044f\u043c\u043e \u0432 \u0437\u0430\u043f\u0440\u043e\u0441\u0435, \u0438\u043b\u0438 \u00ab\u042d\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u0440\u043d\u0430\u044f \u0442\u0440\u0435\u0445\u0445\u043e\u0434\u043e\u0432\u043a\u0430\u00bb&#187;<\/a>. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u0441\u044f <code>UNION ALL<\/code> \u0441 \u043f\u0440\u043e\u0442\u0438\u0432\u043e\u043f\u043e\u043b\u043e\u0436\u043d\u044b\u043c\u0438 \u0443\u0441\u043b\u043e\u0432\u0438\u044f\u043c\u0438:<\/p>\n<pre><code class=\"sql\">, rec_03 AS (   SELECT     '{}'::json[] fixpath   , json_agg(row_to_json(T)) matrix   , NULL::json result   , TRUE has_many   , FALSE has_none   FROM     base T UNION ALL   (     -- \"\u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0443\u0435\u043c\" \u0440\u0435\u043a\u0443\u0440\u0441\u0438\u0432\u043d\u0443\u044e \u0447\u0430\u0441\u0442\u044c, \u0447\u0442\u043e\u0431\u044b \u043e\u0431\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f \u043a \u043d\u0435\u0439 \u043c\u043d\u043e\u0433\u043e\u043a\u0440\u0430\u0442\u043d\u043e     WITH mv AS (       TABLE rec_03     )     (       -- \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0435 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430 \"\u0432\u044b\u0447\u0435\u0440\u043a\u0438\u0432\u0430\u043d\u0438\u0439\"       SELECT         mv.fixpath       , mv.matrix       , T.result       , T.has_many       , T.has_none       FROM         mv       , LATERAL (           WITH RECURSIVE unpack AS (             SELECT               *             FROM               json_to_recordset(coalesce(result, matrix)) unpack(x bigint, y bigint, cell bigint[])           )           , rec_02 AS (             SELECT               1 lvl             , *             FROM               unpack           UNION ALL             -- ...           )           , last_iter AS (             SELECT               x             , y             , cell             FROM               rec_02             WHERE               lvl = (SELECT max(lvl) FROM rec_02)           )           SELECT             json_agg(row_to_json(T)) result           , bool_or(array_length(cell, 1) &gt; 1) has_many   -- \u0435\u0441\u0442\u044c \u044f\u0447\u0435\u0439\u043a\u0438 \u0441 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u043c\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f\u043c\u0438           , bool_or(coalesce(cell, '{}') = '{}') has_none -- \u0435\u0441\u0442\u044c \u043f\u0443\u0441\u0442\u044b\u0435 \u044f\u0447\u0435\u0439\u043a\u0438           FROM             last_iter T         ) T       WHERE         -- \u043d\u0435\u0447\u0435\u0442\u043d\u044b\u0439 \u0448\u0430\u0433         mv.result IS NULL     UNION ALL       -- \u0444\u0438\u043a\u0441\u0430\u0446\u0438\u044f \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \u044f\u0447\u0435\u0439\u043a\u0438       SELECT         T.fixpath       , T.matrix       , NULL       , mv.has_many       , mv.has_none       FROM         mv       , LATERAL (           WITH unpack AS (             SELECT               *             FROM               json_to_recordset(coalesce(result, matrix)) unpack(x bigint, y bigint, cell bigint[])           )           -- ... \u043f\u0435\u0440\u0435\u0441\u0431\u043e\u0440\u043a\u0430 \u043c\u0430\u0442\u0440\u0438\u0446\u044b         ) T       WHERE         -- \u0447\u0435\u0442\u043d\u044b\u0439 \u0448\u0430\u0433         mv.result IS NOT NULL AND         -- \u043f\u043e\u043a\u0430 \u043d\u0435\u0442 \u043f\u0443\u0441\u0442\u044b\u0445 \u044f\u0447\u0435\u0435\u043a, \u043d\u043e \u0435\u0441\u0442\u044c \u043d\u0435\u0437\u0430\u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435         mv.has_many AND         NOT mv.has_none     )   ) )<\/code><\/pre>\n<p>\u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435, \u0447\u0442\u043e <code>unpack<\/code> \u0445\u043e\u0442\u044c \u0438 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u043e, \u043d\u0435 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c &#171;\u0432\u044b\u043d\u0435\u0441\u0435\u043d \u0437\u0430 \u0441\u043a\u043e\u0431\u043a\u0438&#187;, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0442\u043e\u0433\u0434\u0430 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0442\u044c\u0441\u044f \u043a\u043e \u0432\u0441\u0435\u043c \u0437\u0430\u043f\u0438\u0441\u044f\u043c \u0440\u0435\u043a\u0443\u0440\u0441\u0438\u0432\u043d\u043e\u0433\u043e \u0441\u0435\u0433\u043c\u0435\u043d\u0442\u0430 <code>mv<\/code> &#8212; \u0430 \u0438\u0445 \u0442\u0430\u043c \u043f\u043e\u0441\u043b\u0435 <code>unnest<\/code> \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0433\u043e \u0448\u0430\u0433\u0430 \u0437\u0430\u0432\u0435\u0434\u043e\u043c\u043e \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e. \u0410 \u0442\u0430\u043a \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 <code>LATERAL<\/code> \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043d\u0430\u043c &#171;\u0440\u0430\u0441\u043f\u0430\u043a\u043e\u0432\u044b\u0432\u0430\u0442\u044c&#187; \u043a\u0430\u0436\u0434\u0443\u044e \u0441\u0442\u0440\u043e\u043a\u0443 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e.<\/p>\n<h2>\u0420\u0438\u0441\u0443\u0435\u043c \u0438\u0442\u043e\u0433\u043e\u0432\u0443\u044e \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0443<\/h2>\n<pre><code class=\"sql\">-- \u043d\u0430\u0445\u043e\u0434\u0438\u043c \u0437\u0430\u043f\u0438\u0441\u044c \u0441 \u0440\u0435\u0448\u0435\u043d\u0438\u0435\u043c , unpack AS (   SELECT     *   FROM     json_to_recordset((       SELECT         result       FROM         rec_03       WHERE         NOT has_many AND -- \u043d\u0435\u0442 \u0432\u0430\u0440\u0438\u0430\u0442\u0438\u0432\u043d\u043e\u0441\u0442\u0438         NOT has_none     -- \u043d\u0435\u0442 \u0437\u0430\u043d\u0443\u043b\u0435\u043d\u0438\u0439       LIMIT 1     )) unpack(x bigint, y bigint, cell bigint[]) ) -- \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u043c \u0432 \u043c\u0430\u0442\u0440\u0438\u0446\u0443 SELECT   string_agg(     lpad(cell[1]::text, (SELECT length(m::text) FROM side))   , ' '   ORDER BY x   ) line FROM   unpack GROUP BY   y ORDER BY   y;<\/code><\/pre>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/ebe\/2a5\/aa7\/ebe2a5aa7e8d439afbd4256b38346fd4.png\" width=\"1375\" height=\"1452\"><figcaption><\/figcaption><\/figure>\n<p>\u041e\u0431\u0449\u0435\u0435 \u0432\u0440\u0435\u043c\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u044d\u0442\u043e\u0433\u043e \u0430\u0434\u043e\u0432\u043e\u0433\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0430 &#8212; <strong>\u0432\u0441\u0435\u0433\u043e 250ms<\/strong>, \u043d\u0443, \u0430 \u043f\u043e\u043b\u043d\u044b\u0439 \u0435\u0433\u043e \u0442\u0435\u043a\u0441\u0442 \u0432\u044b \u0443\u0436\u0435 \u0432\u0438\u0434\u0435\u043b\u0438 \u0432 \u043d\u0430\u0447\u0430\u043b\u0435 \u0441\u0442\u0430\u0442\u044c\u0438. (:<\/p>\n<p>\u041d\u0430\u0434\u0435\u044e\u0441\u044c, \u0447\u0442\u043e-\u0442\u043e \u0434\u043b\u044f \u0441\u0435\u0431\u044f \u043d\u043e\u0432\u043e\u0435 \u0438\u043b\u0438 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e\u0435 \u0432 \u043d\u0435\u043c \u043d\u0430\u0439\u0434\u0435\u0442\u0435 \u0438 \u0432\u044b.<\/p>\n<\/div>\n<p> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/company\/tensor\/blog\/552790\/\"> https:\/\/habr.com\/ru\/company\/tensor\/blog\/552790\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"\n<div class=\"post__text post__text_v2\" id=\"post-content-body\">\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p>\u041c\u043d\u043e\u0433\u0438\u0435 \u0437\u043d\u0430\u044e\u0442 \u043f\u0440\u0430\u0432\u0438\u043b\u0430 \u044d\u0442\u043e\u0439 \u0433\u043e\u043b\u043e\u0432\u043e\u043b\u043e\u043c\u043a\u0438 (<a href=\"http:\/\/www.playsudoku.ru\/skyscrapers.html\">Skyscrapers<\/a>):<\/p>\n<blockquote>\n<p>\u041f\u0435\u0440\u0435\u0434 \u0432\u0430\u043c\u0438 \u0432\u0438\u0434 \u0441\u0432\u0435\u0440\u0445\u0443 \u043d\u0430 \u0433\u043e\u0440\u043e\u0434\u0441\u043a\u043e\u0439 \u043a\u0432\u0430\u0440\u0442\u0430\u043b. \u0412 \u043a\u0430\u0436\u0434\u043e\u0439 \u043a\u043b\u0435\u0442\u043a\u0435 \u0441\u0442\u043e\u0438\u0442 &#171;\u043d\u0435\u0431\u043e\u0441\u043a\u0440\u0435\u0431&#187; \u0432\u044b\u0441\u043e\u0442\u043e\u0439, \u0440\u0430\u0432\u043d\u043e\u0439 \u0447\u0438\u0441\u043b\u0443 \u0432 \u044d\u0442\u043e\u0439 \u043a\u043b\u0435\u0442\u043a\u0435. \u0427\u0438\u0441\u043b\u0430 \u0441 \u0431\u043e\u043a\u043e\u0432 \u0441\u0435\u0442\u043a\u0438 \u043e\u0437\u043d\u0430\u0447\u0430\u044e\u0442 <strong>\u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e &#171;\u043d\u0435\u0431\u043e\u0441\u043a\u0440\u0435\u0431\u043e\u0432&#187;, \u0432\u0438\u0434\u0438\u043c\u044b\u0445<\/strong> \u0438\u0437 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0439 \u0441\u0442\u0440\u043e\u043a\u0438 \u0438\u043b\u0438 \u0441\u0442\u043e\u043b\u0431\u0446\u0430, \u0435\u0441\u043b\u0438 \u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043e\u0442 \u044d\u0442\u043e\u0433\u043e \u0447\u0438\u0441\u043b\u0430.<\/p>\n<p>\u0417\u0430\u0434\u0430\u0447\u0430: \u0437\u0430\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u0441\u0435\u0442\u043a\u0443 \u0447\u0438\u0441\u043b\u0430\u043c\u0438 \u0442\u0430\u043a, \u0447\u0442\u043e\u0431\u044b \u0432 \u043a\u0430\u0436\u0434\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0435 \u0438 \u0432 \u043a\u0430\u0436\u0434\u043e\u043c \u0441\u0442\u043e\u043b\u0431\u0446\u0435 <strong>\u043a\u0430\u0436\u0434\u043e\u0435 \u0447\u0438\u0441\u043b\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u043e\u0441\u044c \u043b\u0438\u0448\u044c \u0435\u0434\u0438\u043d\u043e\u0436\u0434\u044b<\/strong>.<\/p>\n<\/blockquote>\n<p>\u041f\u043e\u043d\u044f\u0442\u043d\u043e, \u0447\u0442\u043e \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u043e\u043c \u043f\u043e\u043b\u043d\u043e\u0433\u043e \u043f\u0435\u0440\u0435\u0431\u043e\u0440\u0430 \u043c\u043e\u0436\u043d\u043e \u0440\u0435\u0448\u0438\u0442\u044c \u0447\u0442\u043e \u0443\u0433\u043e\u0434\u043d\u043e, \u043d\u043e &#8212; \u0437\u0430 \u044d\u043a\u0441\u043f\u043e\u043d\u0435\u043d\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u0435 \u0432\u0440\u0435\u043c\u044f. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043c\u044b \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u043c \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0442\u0430\u043a\u043e\u0439 SQL-\u0437\u0430\u043f\u0440\u043e\u0441, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0440\u0435\u0448\u0438\u0442 \u043d\u0430\u043c \u0442\u0430\u043a\u0443\u044e \u0433\u043e\u043b\u043e\u0432\u043e\u043b\u043e\u043c\u043a\u0443 \u0437\u0430 \u043f\u0440\u0438\u0435\u043c\u043b\u0435\u043c\u043e\u0435 \u0432\u0440\u0435\u043c\u044f.<\/p>\n<p>\u0417\u0430\u0447\u0435\u043c \u0436\u0435 \u0434\u0435\u043b\u0430\u0442\u044c \u044d\u0442\u043e \u043d\u0430 SQL? \u041f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u043c\u043e\u0436\u0435\u043c! \u0410 \u0437\u0430\u043e\u0434\u043d\u043e \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u044d\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 <strong>\u043d\u0430\u0443\u0447\u0438\u0442\u044c\u0441\u044f \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u0438\u0440\u043e\u0432\u0430\u0442\u044c &#171;\u043e\u0447\u0435\u043d\u044c \u0441\u043b\u043e\u0436\u043d\u044b\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b&#187;<\/strong>, \u0447\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u0438\u0433\u043e\u0434\u0438\u0442\u044c\u0441\u044f \u0438 \u0432 \u043e\u0431\u044b\u0447\u043d\u043e\u0439 \u0440\u0430\u0431\u043e\u0442\u0435.<\/p>\n<h2>\u0412\u043e\u0437\u044c\u043c\u0435\u043c \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u0439 \u043f\u0440\u0438\u043c\u0435\u0440<\/h2>\n<p>\u041b\u044e\u0431\u043e\u0439 \u0445\u043e\u0442\u044c \u0441\u043a\u043e\u043b\u044c\u043a\u043e-\u0442\u043e \u0441\u043b\u043e\u0436\u043d\u044b\u0439 SQL-\u0437\u0430\u043f\u0440\u043e\u0441 \u043b\u0443\u0447\u0448\u0435 \u0432\u0441\u0435\u0433\u043e \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u043d\u0430 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u0435. \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0432\u043e\u0437\u044c\u043c\u0435\u043c \u0434\u043b\u044f \u043d\u0435\u0433\u043e \u0441 \u0441\u0430\u0439\u0442\u0430 <a href=\"http:\/\/www.playsudoku.ru\/\">playsudoku.ru<\/a> \u043e\u0434\u0438\u043d \u0438\u0437 &#171;\u0441\u043b\u043e\u0436\u043d\u044b\u0445&#187; \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432 \u044d\u0442\u043e\u0439 \u0433\u043e\u043b\u043e\u0432\u043e\u043b\u043e\u043c\u043a\u0438 <a href=\"http:\/\/www.playsudoku.ru\/skyscrapers\/sky_9_3_01.html\">\u0432 \u0440\u0430\u0437\u043c\u0435\u0440\u0435 9&#215;9<\/a>:<\/p>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<details class=\"spoiler\">\n<summary>TL; DR &#8212; \u043d\u0435 \u0437\u0430\u0433\u043b\u044f\u0434\u044b\u0432\u0430\u0439\u0442\u0435 \u0431\u0435\u0437 \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0438!<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"sql\">WITH RECURSIVE src AS (   SELECT     x - 1 x   , y - 1 y   , nullif(n, '.')::integer n   FROM     (VALUES( -- http:\/\/www.playsudoku.ru\/skyscrapers\/sky_9_3_01.html $$ . 4 . 3 3 2 1 3 5 2 . . . 2 . . . . . . . 3 3 . . . . . . . . . 1 3 2 . 6 . 7 . 4 . . 3 2 . . 1 . . . 6 . 7 2 3 . . . 4 . 7 . . . 4 2 3 . 2 . . . 5 . . 2 1 . . 5 . 6 . 2 . 4 3 4 . . . . . . . . . . 4 . . . . . . . 7 . 3 . 3 3 2 3 4 6 1 2 5 . $$     )) T(s)   , LATERAL       regexp_split_to_table(regexp_replace(s, '(^\\n|\\n$)', '', 'g'), '\\n+')         WITH ORDINALITY AS L(line, y)   , LATERAL       regexp_split_to_table(line, '\\s+')         WITH ORDINALITY AS C(n, x) ) -- \u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c \"\u0431\u043e\u043a\u043e\u0432\u044b\u0435\" \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f , side AS (   SELECT     m - 1 m   , Y.*   FROM     (       SELECT         max(x) m       FROM         src     ) X   , LATERAL (       SELECT         array_agg(n ORDER BY x) FILTER(WHERE y = 0 AND x &gt; 0 AND x &lt; m) u       , array_agg(n ORDER BY x) FILTER(WHERE y = m AND x &gt; 0 AND x &lt; m) d       , array_agg(n ORDER BY y) FILTER(WHERE x = 0 AND y &gt; 0 AND y &lt; m) l       , array_agg(n ORDER BY y) FILTER(WHERE x = m AND y &gt; 0 AND y &lt; m) r       FROM         src     ) Y ) -- \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u043c \u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u044f , fix AS (   SELECT     x   , y   , array_agg(n) FILTER(       WHERE         coalesce( -- \u0437\u0430\u0449\u0438\u0442\u0430 \u043e\u0442 \u043d\u0435\u0437\u0430\u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0431\u043e\u043a\u043e\u0432\u043e\u0433\u043e \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f           NOT(             -- \u0435\u0434\u0438\u043d\u0438\u0447\u043a\u0430 \u043d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 =&gt; \u043c\u0430\u043a\u0441\u0438\u043c\u0443\u043c \u0432 \u0441\u043e\u0441\u0435\u0434\u043d\u0435\u0439 \u044f\u0447\u0435\u0439\u043a\u0435             (l[y] = 1 AND x = 1 AND n &lt; m) OR             (r[y] = 1 AND x = m AND n &lt; m) OR             (u[x] = 1 AND y = 1 AND n &lt; m) OR             (d[x] = 1 AND y = m AND n &lt; m) OR             -- \u0440\u0430\u0441\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0434\u043e \"\u0431\u043e\u0440\u0442\u0430\"             l[y] + n &gt; m + x OR             u[x] + n &gt; m + y OR             r[y] + n &gt; m + (m - x + 1) OR             d[x] + n &gt; m + (m - y + 1)           )         , TRUE         )     ) cell   FROM     side   , LATERAL       generate_series(1, m) x -- \"\u0446\u0438\u043a\u043b\" \u043f\u043e X   , LATERAL       generate_series(1, m) y -- \"\u0446\u0438\u043a\u043b\" \u043f\u043e Y   , LATERAL       generate_series(1, m) n -- \"\u0446\u0438\u043a\u043b\" \u043f\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f\u043c   GROUP BY     x, y ) , base AS (   SELECT     x   , y   , CASE       WHEN n IS NOT NULL THEN ARRAY[n] -- \u043f\u043e\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c \u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f       ELSE cell     END cell   FROM     fix   NATURAL LEFT JOIN     src   ORDER BY     x, y ) , rec_03 AS (   SELECT     '{}'::json[] fixpath   , json_agg(row_to_json(T)) matrix   , NULL::json result   , TRUE has_many   , FALSE has_none   FROM     base T UNION ALL   (     WITH mv AS (       TABLE rec_03     )     (       -- \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0435 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430 \"\u0432\u044b\u0447\u0435\u0440\u043a\u0438\u0432\u0430\u043d\u0438\u0439\"       SELECT         mv.fixpath       , mv.matrix       , T.result       , T.has_many       , T.has_none       FROM         mv       , LATERAL (           WITH RECURSIVE unpack AS (             SELECT               *             FROM               json_to_recordset(coalesce(result, matrix)) unpack(x bigint, y bigint, cell bigint[])           )           , rec_02 AS (             SELECT               0 lvl             , *             FROM               unpack           UNION ALL             -- \"\u0432\u044b\u0447\u0435\u0440\u043a\u0438\u0432\u0430\u043d\u0438\u0435\" \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439             (               WITH RECURSIVE mv AS (                 TABLE rec_02               )               , rec_01 AS (                 TABLE mv               UNION ALL                 (                   WITH mv AS (                     TABLE rec_01                   )                   , step0 AS (                     SELECT                       *                     , cell cell_new                     FROM                       mv                     WHERE                       NOT EXISTS(                         SELECT                           NULL                         FROM                           mv                         WHERE                           cell = '{}'                       )                   )                   -- \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0435 \u043f\u043e \u0441\u0442\u043e\u043b\u0431\u0446\u0443\/\u0441\u0442\u0440\u043e\u043a\u0435 \u043e\u0442 \u0437\u0430\u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439                   , heur_a AS (                     SELECT                       x                     , y                     , array_agg(DISTINCT cell_new[1]) cell_cross                     FROM                       step0                     WHERE                       array_length(cell, 1) = 1 -- \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0432 \u0442\u043e\u0447\u043a\u0435                     GROUP BY                       GROUPING SETS((x), (y))   -- \u0433\u0440\u0443\u043f\u043f\u0438\u0440\u0443\u0435\u043c \u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e \u0432 \u0434\u0432\u0443\u0445 \u0440\u0430\u0437\u0440\u0435\u0437\u0430\u0445                   )                   , step1 AS (                     SELECT                       lvl                     , s.x                     , s.y                     , cell                     , CASE                         -- \u0432\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u043c \u043d\u043e\u0432\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f \u043d\u0435\u0437\u0430\u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u044f\u0447\u0435\u0435\u043a                         WHEN array_length(cell_new, 1) &gt; 1 THEN                           ARRAY( -- \u0440\u0430\u0437\u043d\u043e\u0441\u0442\u044c \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432                             SELECT                               unnest(s.cell)                           EXCEPT                             SELECT                               unnest(hx.cell_cross)                           EXCEPT                             SELECT                               unnest(hy.cell_cross)                           )                         ELSE cell_new                       END cell_new                     FROM                       step0 s                     LEFT JOIN                       heur_a hx                         ON hx.x = s.x                     LEFT JOIN                       heur_a hy                         ON hy.y = s.y                   )                   -- \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u0430\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u0430\u044f \u043f\u043e\u0437\u0438\u0446\u0438\u044f \u0434\u043b\u044f \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f - \u043d\u0443\u0436\u043d\u0430\u044f                   , heur_b AS (                     SELECT DISTINCT                       s.x                     , s.y                     , ARRAY[n] cell_single                     FROM                       (                         SELECT                           *                         FROM                           step1                         WHERE                           array_length(cell_new, 1) &gt; 1                       ) s                     JOIN                       (                         SELECT                           x                         , y                         , unnest(cell_new) n                         FROM                           step1                         GROUP BY                           GROUPING SETS((n, x), (n, y)) -- \u0433\u0440\u0443\u043f\u043f\u0438\u0440\u0443\u0435\u043c \u043f\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044e \u0438 \u0441\u0442\u0440\u043e\u043a\u0435\/\u0441\u0442\u043e\u043b\u0431\u0446\u0443                         HAVING                           count(*) = 1 -- \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0441\u0442\u044c \u043f\u043e\u0437\u0438\u0446\u0438\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0432 \u0433\u0440\u0443\u043f\u043f\u0435                       ) T                         ON                           n = ANY(cell_new) AND                           (T.x = s.x OR T.y = s.y)                   )                   , step2 AS (                     SELECT                       lvl                     , x                     , y                     , cell                     , coalesce(cell_single, cell_new) cell_new                     FROM                       step1                     NATURAL LEFT JOIN                       heur_b                   )                   SELECT                     lvl + 1                   , x                   , y                   , cell_new cell                   FROM                     step2                   WHERE                     -- \u0438\u0442\u0435\u0440\u0438\u0440\u0443\u0435\u043c, \u043f\u043e\u043a\u0430 \u0445\u043e\u0442\u044c \u0447\u0442\u043e-\u0442\u043e \"\u0432\u044b\u0447\u0435\u0440\u043a\u0438\u0432\u0430\u0435\u0442\u0441\u044f\"                     EXISTS(                       SELECT                         NULL                       FROM                         step2                       WHERE                         array_length(cell_new, 1) &lt; array_length(cell, 1)                     )                 )               )               -- \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0439 \u0448\u0430\u0433 \u0440\u0435\u043a\u0443\u0440\u0441\u0438\u0438               , step3 AS (                 SELECT                   *                 FROM                   rec_01                 WHERE                   lvl = (SELECT max(lvl) FROM rec_01)               )               -- \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0435 \u0432\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u043f\u043e \u0441\u0442\u043e\u043b\u0431\u0446\u0430\u043c               , heur_cx AS (                 -- \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u043c \u0432\u0441\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u0435 \u043a\u043e\u043c\u0431\u0438\u043d\u0430\u0446\u0438\u0438 \u0431\u0435\u0437 \u043f\u043e\u0432\u0442\u043e\u0440\u043e\u0432                 WITH RECURSIVE gen AS (                   SELECT                     generate_series(1, m) x                   , 0::bigint y                   , '{}'::bigint[] comb                   FROM                     side                 UNION ALL                   SELECT                     s.x                   , s.y                   , comb || n                   FROM                     gen                   JOIN                     step3 s                       ON (s.x, s.y) = (gen.x, gen.y + 1)                   JOIN LATERAL                     unnest(cell) n                       ON n &lt;&gt; ALL(comb) -- \u0437\u0430\u043f\u0440\u0435\u0442 \u043f\u043e\u0432\u0442\u043e\u0440\u0430 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f                 )                 SELECT                   gen.x                 , ord.y                 , array_agg(DISTINCT n) cell_y                 FROM                   side                 JOIN                   gen                     ON array_length(comb, 1) = m -- \u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c \u0442\u043e\u043b\u044c\u043a\u043e \u0438\u0442\u043e\u0433\u043e\u0432\u044b\u0435 \u043a\u043e\u043c\u0431\u0438\u043d\u0430\u0446\u0438\u0438 \u043f\u043e\u043b\u043d\u043e\u0433\u043e<\/code><\/pre>\n<\/div>\n<\/details>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-321781","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/321781","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=321781"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/321781\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=321781"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=321781"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=321781"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}