SQL HowTo: Π½Π°ΠΏΠΈΡˆΠ΅Ρ‚Π΅ while-Ρ†ΠΈΠΊΡŠΠ» Π΄ΠΈΡ€Π΅ΠΊΡ‚Π½ΠΎ Π² заявката ΠΈΠ»ΠΈ β€žΠ•Π»Π΅ΠΌΠ΅Π½Ρ‚Π°Ρ€Π½ΠΎ Ρ‚Ρ€ΠΈΠΏΠΎΡΠΎΡ‡Π½ΠΎβ€œ

ΠŸΠ΅Ρ€ΠΈΠΎΠ΄ΠΈΡ‡Π½ΠΎ възниква Π·Π°Π΄Π°Ρ‡Π°Ρ‚Π° Π·Π° Ρ‚ΡŠΡ€ΡΠ΅Π½Π΅ Π½Π° ΡΠ²ΡŠΡ€Π·Π°Π½ΠΈ Π΄Π°Π½Π½ΠΈ Ρ‡Ρ€Π΅Π· Π½Π°Π±ΠΎΡ€ ΠΎΡ‚ ΠΊΠ»ΡŽΡ‡ΠΎΠ²Π΅, Π΄ΠΎΠΊΠ°Ρ‚ΠΎ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠΌ нСобходимия ΠΎΠ±Ρ‰ Π±Ρ€ΠΎΠΉ записи.

Най-β€žΡ€Π΅Π°Π»ΠΈΡΡ‚ΠΈΡ‡Π½ΠΈΡΡ‚β€œ ΠΏΡ€ΠΈΠΌΠ΅Ρ€ Π΅ Π΄Π° сС ΠΏΠΎΠΊΠ°ΠΆΠ΅ 20 Π½Π°ΠΉ-стари ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΠΈ, ΠΈΠ·Π±Ρ€ΠΎΠ΅Π½ΠΈ Π² списъка Π½Π° слуТитСлитС (Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€ Π² Ρ€Π°ΠΌΠΊΠΈΡ‚Π΅ Π½Π° ΡΡŠΡ‰ΠΈΡ ΠΎΡ‚Π΄Π΅Π»). Π—Π° Ρ€Π°Π·Π»ΠΈΡ‡Π½ΠΈ управлСнски "Ρ‚Π°Π±Π»Π°" с ΠΊΡ€Π°Ρ‚ΠΊΠΈ Ρ€Π΅Π·ΡŽΠΌΠ΅Ρ‚Π° Π½Π° областитС Π½Π° Ρ€Π°Π±ΠΎΡ‚Π° ΠΏΠΎΠ΄ΠΎΠ±Π½Π° Ρ‚Π΅ΠΌΠ° сС изисква доста чСсто.

SQL HowTo: Π½Π°ΠΏΠΈΡˆΠ΅Ρ‚Π΅ while-Ρ†ΠΈΠΊΡŠΠ» Π΄ΠΈΡ€Π΅ΠΊΡ‚Π½ΠΎ Π² заявката ΠΈΠ»ΠΈ β€žΠ•Π»Π΅ΠΌΠ΅Π½Ρ‚Π°Ρ€Π½ΠΎ Ρ‚Ρ€ΠΈΠΏΠΎΡΠΎΡ‡Π½ΠΎβ€œ

Π’ статията Ρ‰Π΅ Ρ€Π°Π·Π³Π»Π΅Π΄Π°ΠΌΠ΅ внСдряванСто Π½Π° PostgreSQL Π½Π° β€žΠ½Π°ΠΈΠ²Π½Π°β€œ вСрсия Π·Π° Ρ€Π΅ΡˆΠ°Π²Π°Π½Π΅ Π½Π° Ρ‚Π°ΠΊΡŠΠ² ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌ, β€žΠΏΠΎ-ΡƒΠΌΠ΅Π½β€œ ΠΈ ΠΌΠ½ΠΎΠ³ΠΎ слоТСн Π°Π»Π³ΠΎΡ€ΠΈΡ‚ΡŠΠΌ "Ρ†ΠΈΠΊΡŠΠ»" Π² SQL с условиС Π·Π° ΠΈΠ·Ρ…ΠΎΠ΄ ΠΎΡ‚ Π½Π°ΠΌΠ΅Ρ€Π΅Π½ΠΈΡ‚Π΅ Π΄Π°Π½Π½ΠΈ, ΠΊΠΎΠΈΡ‚ΠΎ ΠΌΠΎΠ³Π°Ρ‚ Π΄Π° Π±ΡŠΠ΄Π°Ρ‚ ΠΏΠΎΠ»Π΅Π·Π½ΠΈ ΠΊΠ°ΠΊΡ‚ΠΎ Π·Π° ΠΎΠ±Ρ‰ΠΎ Ρ€Π°Π·Π²ΠΈΡ‚ΠΈΠ΅, Ρ‚Π°ΠΊΠ° ΠΈ Π·Π° ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°Π½Π΅ Π² Π΄Ρ€ΡƒΠ³ΠΈ ΠΏΠΎΠ΄ΠΎΠ±Π½ΠΈ случаи.

НСка Π²Π·Π΅ΠΌΠ΅ΠΌ Π½Π°Π±ΠΎΡ€ ΠΎΡ‚ тСстови Π΄Π°Π½Π½ΠΈ ΠΎΡ‚ ΠΏΡ€Π΅Π΄ΠΈΡˆΠ½Π° статия. Π’Π°ΠΊΠ° Ρ‡Π΅ ΠΈΠ·Ρ…ΠΎΠ΄Π½ΠΈΡ‚Π΅ записи Π΄Π° Π½Π΅ β€žΡΠΊΠ°Ρ‡Π°Ρ‚β€œ ΠΎΡ‚ Π²Ρ€Π΅ΠΌΠ΅ Π½Π° Π²Ρ€Π΅ΠΌΠ΅, ΠΊΠΎΠ³Π°Ρ‚ΠΎ сортиранитС стойности ΡΡŠΠ²ΠΏΠ°Π΄Π°Ρ‚, Ρ€Π°Π·ΡˆΠΈΡ€Π΅Ρ‚Π΅ прСдмСтния индСкс Ρ‡Ρ€Π΅Π· добавянС Π½Π° ΠΏΡŠΡ€Π²ΠΈΡ‡Π΅Π½ ΠΊΠ»ΡŽΡ‡. Π’ ΡΡŠΡ‰ΠΎΡ‚ΠΎ Π²Ρ€Π΅ΠΌΠ΅ Ρ‚ΠΎΠ²Π° Π²Π΅Π΄Π½Π°Π³Π° Ρ‰Π΅ ΠΌΡƒ ΠΏΡ€ΠΈΠ΄Π°Π΄Π΅ уникалност ΠΈ Ρ‰Π΅ Π½ΠΈ Π³Π°Ρ€Π°Π½Ρ‚ΠΈΡ€Π° уникалността Π½Π° Ρ€Π΅Π΄Π° Π½Π° сортиранС:

CREATE INDEX ON task(owner_id, task_date, id);
-- Π° старый - ΡƒΠ΄Π°Π»ΠΈΠΌ
DROP INDEX task_owner_id_task_date_idx;

ΠšΠ°ΠΊΡ‚ΠΎ сС Ρ‡ΡƒΠ²Π°, Ρ‚Π°ΠΊΠ° сС пишС

ΠŸΡŠΡ€Π²ΠΎ, Π½Π΅ΠΊΠ° скицирамС Π½Π°ΠΉ-простата вСрсия Π½Π° заявката, ΠΏΡ€Π΅Π΄Π°Π²Π°ΠΉΠΊΠΈ ΠΈΠ΄Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ‚ΠΎΡ€ΠΈΡ‚Π΅ Π½Π° ΠΈΠ·ΠΏΡŠΠ»Π½ΠΈΡ‚Π΅Π»ΠΈΡ‚Π΅ масив ΠΊΠ°Ρ‚ΠΎ Π²Ρ…ΠΎΠ΄:

SELECT
  *
FROM
  task
WHERE
  owner_id = ANY('{1,2,4,8,16,32,64,128,256,512}'::integer[])
ORDER BY
  task_date, id
LIMIT 20;

SQL HowTo: Π½Π°ΠΏΠΈΡˆΠ΅Ρ‚Π΅ while-Ρ†ΠΈΠΊΡŠΠ» Π΄ΠΈΡ€Π΅ΠΊΡ‚Π½ΠΎ Π² заявката ΠΈΠ»ΠΈ β€žΠ•Π»Π΅ΠΌΠ΅Π½Ρ‚Π°Ρ€Π½ΠΎ Ρ‚Ρ€ΠΈΠΏΠΎΡΠΎΡ‡Π½ΠΎβ€œ
[Π²ΠΈΠΆΡ‚Π΅ expand.tensor.ru]

Малко Ρ‚ΡŠΠΆΠ½ΠΎ - ΠΏΠΎΡ€ΡŠΡ‡Π°Ρ…ΠΌΠ΅ само 20 записа ΠΈ Index Scan Π½ΠΈ Π²ΡŠΡ€Π½Π° 960 Ρ€Π΅Π΄Π°, ΠΊΠΎΠΈΡ‚ΠΎ слСд Ρ‚ΠΎΠ²Π° ΡΡŠΡ‰ΠΎ Ρ‚Ρ€ΡΠ±Π²Π°ΡˆΠ΅ Π΄Π° Π±ΡŠΠ΄Π°Ρ‚ сортирани ... И Π½Π΅ΠΊΠ° сС ΠΎΠΏΠΈΡ‚Π°ΠΌΠ΅ Π΄Π° Ρ‡Π΅Ρ‚Π΅ΠΌ ΠΏΠΎ-ΠΌΠ°Π»ΠΊΠΎ.

unnest + ARRAY

ΠŸΡŠΡ€Π²ΠΎΡ‚ΠΎ ΡΡŠΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅, ΠΊΠΎΠ΅Ρ‚ΠΎ Ρ‰Π΅ Π½ΠΈ ΠΏΠΎΠΌΠΎΠ³Π½Π΅ - Π°ΠΊΠΎ ΠΈΠΌΠ°ΠΌΠ΅ Π½ΡƒΠΆΠ΄Π° ΠΎΠ±Ρ‰ΠΎ 20 сортирани записи, Π΄ΠΎΡΡ‚Π°Ρ‚ΡŠΡ‡Π½ΠΎ Π΅ Π΄Π° сС ΠΏΡ€ΠΎΡ‡Π΅Ρ‚Π°Ρ‚ Π½Π΅ ΠΏΠΎΠ²Π΅Ρ‡Π΅ ΠΎΡ‚ 20, сортирани Π² Π΅Π΄ΠΈΠ½ ΠΈ ΡΡŠΡ‰ΠΈ Ρ€Π΅Π΄ Π·Π° всСки ΠΊΠ»ΡŽΡ‡. Π”ΠΎΠ±Ρ€Π΅, подходящ индСкс (owner_id, task_date, id) ΠΈΠΌΠ°ΠΌΠ΅.

НСка ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°ΠΌΠ΅ ΡΡŠΡ‰ΠΈΡ ΠΌΠ΅Ρ…Π°Π½ΠΈΠ·ΡŠΠΌ Π·Π° ΠΈΠ·Π²Π»ΠΈΡ‡Π°Π½Π΅ ΠΈ "ΠΏΡ€Π΅Π²Ρ€ΡŠΡ‰Π°Π½Π΅ Π² ΠΊΠΎΠ»ΠΎΠ½ΠΈ" вписванС Π² ΠΈΠ½Ρ‚Π΅Π³Ρ€Π°Π»Π½Π° Ρ‚Π°Π±Π»ΠΈΡ†Π°, ΠΊΠ°ΠΊΡ‚ΠΎ Π² послСдната статия. И ΡΡŠΡ‰ΠΎ Ρ‚Π°ΠΊΠ° ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Ρ‚Π΅ ΠΊΠΎΠ½Π²ΠΎΠ»ΡŽΡ†ΠΈΡΡ‚Π° към масив с ΠΏΠΎΠΌΠΎΡ‰Ρ‚Π° Π½Π° функцията ARRAY():

WITH T AS (
  SELECT
    unnest(ARRAY(
      SELECT
        t
      FROM
        task t
      WHERE
        owner_id = unnest
      ORDER BY
        task_date, id
      LIMIT 20 -- ΠΎΠ³Ρ€Π°Π½ΠΈΡ‡ΠΈΠ²Π°Π΅ΠΌ Ρ‚ΡƒΡ‚...
    )) r
  FROM
    unnest('{1,2,4,8,16,32,64,128,256,512}'::integer[])
)
SELECT
  (r).*
FROM
  T
ORDER BY
  (r).task_date, (r).id
LIMIT 20; -- ... ΠΈ Ρ‚ΡƒΡ‚ - Ρ‚ΠΎΠΆΠ΅

SQL HowTo: Π½Π°ΠΏΠΈΡˆΠ΅Ρ‚Π΅ while-Ρ†ΠΈΠΊΡŠΠ» Π΄ΠΈΡ€Π΅ΠΊΡ‚Π½ΠΎ Π² заявката ΠΈΠ»ΠΈ β€žΠ•Π»Π΅ΠΌΠ΅Π½Ρ‚Π°Ρ€Π½ΠΎ Ρ‚Ρ€ΠΈΠΏΠΎΡΠΎΡ‡Π½ΠΎβ€œ
[Π²ΠΈΠΆΡ‚Π΅ expand.tensor.ru]

О, Π²Π΅Ρ‡Π΅ Π΅ ΠΌΠ½ΠΎΠ³ΠΎ ΠΏΠΎ-Π΄ΠΎΠ±Ρ€Π΅! 40% ΠΏΠΎ-Π±ΡŠΡ€Π·ΠΎ ΠΈ 4.5 ΠΏΡŠΡ‚ΠΈ ΠΏΠΎ-ΠΌΠ°Π»ΠΊΠΎ Π΄Π°Π½Π½ΠΈ Ρ‚Ρ€ΡΠ±Π²Π°ΡˆΠ΅ Π΄Π° ΠΏΡ€ΠΎΡ‡Π΅Ρ‚Π°.

ΠœΠ°Ρ‚Π΅Ρ€ΠΈΠ°Π»ΠΈΠ·ΠΈΡ€Π°Π½Π΅ Π½Π° Ρ‚Π°Π±Π»ΠΈΡ‡Π½ΠΈ записи Ρ‡Ρ€Π΅Π· CTEΠ©Π΅ ΠΎΡ‚Π±Π΅Π»Π΅ΠΆΠ°, Ρ‡Π΅ Π² някои случаи ΠΎΠΏΠΈΡ‚ Π·Π° Π½Π΅Π·Π°Π±Π°Π²Π½Π° Ρ€Π°Π±ΠΎΡ‚Π° с ΠΏΠΎΠ»Π΅Ρ‚Π°Ρ‚Π° Π½Π° записа слСд Ρ‚ΡŠΡ€ΡΠ΅Π½Π΅Ρ‚ΠΎ ΠΌΡƒ Π² подзаявка, Π±Π΅Π· β€žΠΎΠ±Π²ΠΈΠ²Π°Π½Π΅β€œ Π² CTE, ΠΌΠΎΠΆΠ΅ Π΄Π° Π΄ΠΎΠ²Π΅Π΄Π΅ Π΄ΠΎ "ΡƒΠΌΠ½ΠΎΠΆΠ΅Π½ΠΈΠ΅" InitPlan ΠΏΡ€ΠΎΠΏΠΎΡ€Ρ†ΠΈΠΎΠ½Π°Π»Π½ΠΎ Π½Π° броя Π½Π° Ρ‚Π΅Π·ΠΈ ΡΡŠΡ‰ΠΈΡ‚Π΅ ΠΏΠΎΠ»Π΅Ρ‚Π°:

SELECT
  ((
    SELECT
      t
    FROM
      task t
    WHERE
      owner_id = 1
    ORDER BY
      task_date, id
    LIMIT 1
  ).*);

Result  (cost=4.77..4.78 rows=1 width=16) (actual time=0.063..0.063 rows=1 loops=1)
  Buffers: shared hit=16
  InitPlan 1 (returns $0)
    ->  Limit  (cost=0.42..1.19 rows=1 width=48) (actual time=0.031..0.032 rows=1 loops=1)
          Buffers: shared hit=4
          ->  Index Scan using task_owner_id_task_date_id_idx on task t  (cost=0.42..387.57 rows=500 width=48) (actual time=0.030..0.030 rows=1 loops=1)
                Index Cond: (owner_id = 1)
                Buffers: shared hit=4
  InitPlan 2 (returns $1)
    ->  Limit  (cost=0.42..1.19 rows=1 width=48) (actual time=0.008..0.009 rows=1 loops=1)
          Buffers: shared hit=4
          ->  Index Scan using task_owner_id_task_date_id_idx on task t_1  (cost=0.42..387.57 rows=500 width=48) (actual time=0.008..0.008 rows=1 loops=1)
                Index Cond: (owner_id = 1)
                Buffers: shared hit=4
  InitPlan 3 (returns $2)
    ->  Limit  (cost=0.42..1.19 rows=1 width=48) (actual time=0.008..0.008 rows=1 loops=1)
          Buffers: shared hit=4
          ->  Index Scan using task_owner_id_task_date_id_idx on task t_2  (cost=0.42..387.57 rows=500 width=48) (actual time=0.008..0.008 rows=1 loops=1)
                Index Cond: (owner_id = 1)
                Buffers: shared hit=4"
  InitPlan 4 (returns $3)
    ->  Limit  (cost=0.42..1.19 rows=1 width=48) (actual time=0.009..0.009 rows=1 loops=1)
          Buffers: shared hit=4
          ->  Index Scan using task_owner_id_task_date_id_idx on task t_3  (cost=0.42..387.57 rows=500 width=48) (actual time=0.009..0.009 rows=1 loops=1)
                Index Cond: (owner_id = 1)
                Buffers: shared hit=4

Π‘ΡŠΡ‰ΠΈΡΡ‚ запис бСшС β€žΡ‚ΡŠΡ€ΡΠ΅Π½β€œ 4 ΠΏΡŠΡ‚ΠΈβ€¦ Π”ΠΎ PostgreSQL 11 Ρ‚ΠΎΠ²Π° ΠΏΠΎΠ²Π΅Π΄Π΅Π½ΠΈΠ΅ сС случва Ρ€Π΅Π΄ΠΎΠ²Π½ΠΎ ΠΈ Ρ€Π΅ΡˆΠ΅Π½ΠΈΠ΅Ρ‚ΠΎ Π΅ Π΄Π° сС β€žΠΎΠ±Π²ΠΈΠ΅β€œ Π² CTE, ΠΊΠΎΠ΅Ρ‚ΠΎ Π΅ бСзусловна Π³Ρ€Π°Π½ΠΈΡ†Π° Π·Π° ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ‚ΠΎΡ€Π° Π² Ρ‚Π΅Π·ΠΈ вСрсии.

рСкурсивСн Π°ΠΊΡƒΠΌΡƒΠ»Π°Ρ‚ΠΎΡ€

Π’ ΠΏΡ€Π΅Π΄ΠΈΡˆΠ½Π°Ρ‚Π° вСрсия Ρ‡Π΅Ρ‚Π΅ΠΌ ΠΎΠ±Ρ‰ΠΎ 200 Ρ€Π΅Π΄Π° Π² ΠΈΠΌΠ΅Ρ‚ΠΎ Π½Π° Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΈΡ‚Π΅ 20. Π’Π΅Ρ‡Π΅ Π½Π΅ 960, Π½ΠΎ ΠΎΡ‰Π΅ ΠΏΠΎ-ΠΌΠ°Π»ΠΊΠΎ - възмоТно Π»ΠΈ Π΅?

НСка сС ΠΎΠΏΠΈΡ‚Π°ΠΌΠ΅ Π΄Π° ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°ΠΌΠ΅ знанията, ΠΎΡ‚ ΠΊΠΎΠΈΡ‚ΠΎ сС Π½ΡƒΠΆΠ΄Π°Π΅ΠΌ ΠΎΠ±Ρ‰ΠΎ 20 записи. ВоСст, Π½ΠΈΠ΅ Ρ‰Π΅ повтарямС ΠΈΠ·Π²Π°ΠΆΠ΄Π°Π½Π΅Ρ‚ΠΎ Π½Π° Π΄Π°Π½Π½ΠΈ само Π΄ΠΎΠΊΠ°Ρ‚ΠΎ Π½Π΅ бъдС достигната Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠ°Ρ‚Π° Π½ΠΈ сума.

Π‘Ρ‚ΡŠΠΏΠΊΠ° 1: Π‘Ρ‚Π°Ρ€Ρ‚ΠΎΠ² списък

ΠžΡ‡Π΅Π²ΠΈΠ΄Π½ΠΎ Π½Π°ΡˆΠΈΡΡ‚ β€žΡ†Π΅Π»Π΅Π²ΠΈβ€œ списък ΠΎΡ‚ 20 записа трябва Π΄Π° Π·Π°ΠΏΠΎΡ‡Π½Π΅ с β€žΠΏΡŠΡ€Π²ΠΈΡ‚Π΅β€œ записи Π·Π° Π΅Π΄ΠΈΠ½ ΠΎΡ‚ Π½Π°ΡˆΠΈΡ‚Π΅ ΠΊΠ»ΡŽΡ‡ΠΎΠ²Π΅ owner_id. Π—Π°Ρ‚ΠΎΠ²Π° ΠΏΡŠΡ€Π²ΠΎ Π½Π°ΠΌΠΈΡ€Π°ΠΌΠ΅ Ρ‚Π°ΠΊΠΈΠ²Π° "ΠΏΡŠΡ€Π²ΠΈ" Π·Π° всСки ΠΎΡ‚ ΠΊΠ»ΡŽΡ‡ΠΎΠ²Π΅Ρ‚Π΅ ΠΈ Π³ΠΎ поставямС Π² списъка, ΠΊΠ°Ρ‚ΠΎ Π³ΠΎ сортирамС Π² Ρ€Π΅Π΄Π°, ΠΊΠΎΠΉΡ‚ΠΎ ΠΆΠ΅Π»Π°Π΅ΠΌ - (task_date, id).

SQL HowTo: Π½Π°ΠΏΠΈΡˆΠ΅Ρ‚Π΅ while-Ρ†ΠΈΠΊΡŠΠ» Π΄ΠΈΡ€Π΅ΠΊΡ‚Π½ΠΎ Π² заявката ΠΈΠ»ΠΈ β€žΠ•Π»Π΅ΠΌΠ΅Π½Ρ‚Π°Ρ€Π½ΠΎ Ρ‚Ρ€ΠΈΠΏΠΎΡΠΎΡ‡Π½ΠΎβ€œ

Π‘Ρ‚ΡŠΠΏΠΊΠ° 2: Π½Π°ΠΌΠ΅Ρ€Π΅Ρ‚Π΅ β€žΡΠ»Π΅Π΄Π²Π°Ρ‰ΠΈΡ‚Π΅β€œ записи

Π‘Π΅Π³Π°, Π°ΠΊΠΎ Π²Π·Π΅ΠΌΠ΅ΠΌ ΠΏΡŠΡ€Π²ΠΈΡ запис ΠΎΡ‚ нашия списък ΠΈ Π·Π°ΠΏΠΎΡ‡Π½Π΅ΠΌ "ΡΡ‚ΡŠΠΏΠΊΠ°" ΠΏΠΎ-Π½Π°Π΄ΠΎΠ»Ρƒ Π² индСкса със Π·Π°ΠΏΠ°Π·Π²Π°Π½Π΅ Π½Π° owner_id-key, Ρ‚ΠΎΠ³Π°Π²Π° всички Π½Π°ΠΌΠ΅Ρ€Π΅Π½ΠΈ записи са само слСдващитС Π² Ρ€Π΅Π·ΡƒΠ»Ρ‚Π°Π½Ρ‚Π½Π°Ρ‚Π° сСлСкция. Π Π°Π·Π±ΠΈΡ€Π° сС, само Π΄ΠΎΠΊΠ°Ρ‚ΠΎ прСсСчСм прилоТСния ΠΊΠ»ΡŽΡ‡ Π²Ρ‚ΠΎΡ€ΠΈ запис Π² списъка.

Ако сС ΠΎΠΊΠ°ΠΆΠ΅, Ρ‡Π΅ смС β€žΠΏΡ€Π΅ΡΠ΅ΠΊΠ»ΠΈβ€œ втория запис, Ρ‚ΠΎΠ³Π°Π²Π° послСдният ΠΏΡ€ΠΎΡ‡Π΅Ρ‚Π΅Π½ запис трябва Π΄Π° сС Π΄ΠΎΠ±Π°Π²ΠΈ към списъка вмСсто ΠΏΡŠΡ€Π²ΠΈΡ (със ΡΡŠΡ‰ΠΈΡ owner_id), слСд ΠΊΠΎΠ΅Ρ‚ΠΎ ΡΠΏΠΈΡΡŠΠΊΡŠΡ‚ сС сортира ΠΎΡ‚Π½ΠΎΠ²ΠΎ.

SQL HowTo: Π½Π°ΠΏΠΈΡˆΠ΅Ρ‚Π΅ while-Ρ†ΠΈΠΊΡŠΠ» Π΄ΠΈΡ€Π΅ΠΊΡ‚Π½ΠΎ Π² заявката ΠΈΠ»ΠΈ β€žΠ•Π»Π΅ΠΌΠ΅Π½Ρ‚Π°Ρ€Π½ΠΎ Ρ‚Ρ€ΠΈΠΏΠΎΡΠΎΡ‡Π½ΠΎβ€œ

ВоСст Π²ΠΈΠ½Π°Π³ΠΈ ΠΏΠΎΠ»ΡƒΡ‡Π°Π²Π°ΠΌΠ΅, Ρ‡Π΅ ΡΠΏΠΈΡΡŠΠΊΡŠΡ‚ ΠΈΠΌΠ° Π½Π΅ ΠΏΠΎΠ²Π΅Ρ‡Π΅ ΠΎΡ‚ Π΅Π΄ΠΈΠ½ запис Π·Π° всСки ΠΎΡ‚ ΠΊΠ»ΡŽΡ‡ΠΎΠ²Π΅Ρ‚Π΅ (Π°ΠΊΠΎ записитС са ΡΠ²ΡŠΡ€ΡˆΠΈΠ»ΠΈ ΠΈ Π½Π΅ смС β€žΠΏΡ€Π΅ΡΠ΅ΠΊΠ»ΠΈβ€œ, Ρ‚ΠΎΠ³Π°Π²Π° ΠΏΡŠΡ€Π²ΠΈΡΡ‚ запис просто Ρ‰Π΅ ΠΈΠ·Ρ‡Π΅Π·Π½Π΅ ΠΎΡ‚ списъка ΠΈ Π½ΠΈΡ‰ΠΎ няма Π΄Π° бъдС Π΄ΠΎΠ±Π°Π²Π΅Π½ΠΎ ), ΠΈ Ρ‚Π΅ Π²ΠΈΠ½Π°Π³ΠΈ сортирани във Π²ΡŠΠ·Ρ…ΠΎΠ΄ΡΡ‰ Ρ€Π΅Π΄ Π½Π° ΠΊΠ»ΡŽΡ‡Π° Π½Π° ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅Ρ‚ΠΎ (task_date, id).

SQL HowTo: Π½Π°ΠΏΠΈΡˆΠ΅Ρ‚Π΅ while-Ρ†ΠΈΠΊΡŠΠ» Π΄ΠΈΡ€Π΅ΠΊΡ‚Π½ΠΎ Π² заявката ΠΈΠ»ΠΈ β€žΠ•Π»Π΅ΠΌΠ΅Π½Ρ‚Π°Ρ€Π½ΠΎ Ρ‚Ρ€ΠΈΠΏΠΎΡΠΎΡ‡Π½ΠΎβ€œ

Π‘Ρ‚ΡŠΠΏΠΊΠ° 3: Π€ΠΈΠ»Ρ‚Ρ€ΠΈΡ€Π°Π½Π΅ ΠΈ Ρ€Π°Π·ΡˆΠΈΡ€ΡΠ²Π°Π½Π΅ Π½Π° записи

Π’ частта ΠΎΡ‚ Ρ€Π΅Π΄ΠΎΠ²Π΅Ρ‚Π΅ Π½Π° Π½Π°ΡˆΠ°Ρ‚Π° рСкурсивна сСлСкция, някои записи rv сС Π΄ΡƒΠ±Π»ΠΈΡ€Π°Ρ‚ - ΠΏΡŠΡ€Π²ΠΎ Π½Π°ΠΌΠΈΡ€Π°ΠΌΠ΅ ΠΊΠ°Ρ‚ΠΎ β€žΠΏΡ€Π΅ΡΠΈΡ‡Π°Π½Π΅ Π½Π° Π³Ρ€Π°Π½ΠΈΡ†Π°Ρ‚Π° Π½Π° 2-Ρ€ΠΈ запис ΠΎΡ‚ ΡΠΏΠΈΡΡŠΠΊΠ°β€œ, Π° слСд Ρ‚ΠΎΠ²Π° замСствамС ΠΊΠ°Ρ‚ΠΎ 1-Π²ΠΈ ΠΎΡ‚ списъка. И Ρ‚Π°ΠΊΠ°, ΠΏΡŠΡ€Π²ΠΎΡ‚ΠΎ срСщанС трябва Π΄Π° бъдС Ρ„ΠΈΠ»Ρ‚Ρ€ΠΈΡ€Π°Π½ΠΎ.

УТасно послСдно Π·Π°ΠΏΠΈΡ‚Π²Π°Π½Π΅

WITH RECURSIVE T AS (
  -- #1 : заносим Π² список "ΠΏΠ΅Ρ€Π²Ρ‹Π΅" записи ΠΏΠΎ ΠΊΠ°ΠΆΠ΄ΠΎΠΌΡƒ ΠΈΠ· ΠΊΠ»ΡŽΡ‡Π΅ΠΉ Π½Π°Π±ΠΎΡ€Π°
  WITH wrap AS ( -- "ΠΌΠ°Ρ‚Π΅Ρ€ΠΈΠ°Π»ΠΈΠ·ΡƒΠ΅ΠΌ" record'Ρ‹, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΎΠ±Ρ€Π°Ρ‰Π΅Π½ΠΈΠ΅ ΠΊ полям Π½Π΅ Π²Ρ‹Π·Ρ‹Π²Π°Π»ΠΎ умноТСния InitPlan/SubPlan
    WITH T AS (
      SELECT
        (
          SELECT
            r
          FROM
            task r
          WHERE
            owner_id = unnest
          ORDER BY
            task_date, id
          LIMIT 1
        ) r
      FROM
        unnest('{1,2,4,8,16,32,64,128,256,512}'::integer[])
    )
    SELECT
      array_agg(r ORDER BY (r).task_date, (r).id) list -- сортируСм список Π² Π½ΡƒΠΆΠ½ΠΎΠΌ порядкС
    FROM
      T
  )
  SELECT
    list
  , list[1] rv
  , FALSE not_cross
  , 0 size
  FROM
    wrap
UNION ALL
  -- #2 : Π²Ρ‹Ρ‡ΠΈΡ‚Ρ‹Π²Π°Π΅ΠΌ записи 1-Π³ΠΎ ΠΏΠΎ порядку ΠΊΠ»ΡŽΡ‡Π°, ΠΏΠΎΠΊΠ° Π½Π΅ ΠΏΠ΅Ρ€Π΅ΡˆΠ°Π³Π½Π΅ΠΌ Ρ‡Π΅Ρ€Π΅Π· запись 2-Π³ΠΎ
  SELECT
    CASE
      -- Ссли Π½ΠΈΡ‡Π΅Π³ΠΎ Π½Π΅ Π½Π°ΠΉΠ΄Π΅Π½ΠΎ для ΠΊΠ»ΡŽΡ‡Π° 1-ΠΉ записи
      WHEN X._r IS NOT DISTINCT FROM NULL THEN
        T.list[2:] -- ΡƒΠ±ΠΈΡ€Π°Π΅ΠΌ Π΅Π΅ ΠΈΠ· списка
      -- Ссли ΠΌΡ‹ НЕ пСрСсСкли ΠΏΡ€ΠΈΠΊΠ»Π°Π΄Π½ΠΎΠΉ ΠΊΠ»ΡŽΡ‡ 2-ΠΉ записи
      WHEN X.not_cross THEN
        T.list -- просто протягиваСм Ρ‚ΠΎΡ‚ ΠΆΠ΅ список Π±Π΅Π· ΠΌΠΎΠ΄ΠΈΡ„ΠΈΠΊΠ°Ρ†ΠΈΠΉ
      -- Ссли Π² спискС ΡƒΠΆΠ΅ Π½Π΅Ρ‚ 2-ΠΉ записи
      WHEN T.list[2] IS NULL THEN
        -- просто Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅ΠΌ пустой список
        '{}'
      -- пСрСсортировываСм ΡΠ»ΠΎΠ²Π°Ρ€ΡŒ, убирая 1-ю запись ΠΈ добавляя послСднюю ΠΈΠ· Π½Π°ΠΉΠ΄Π΅Π½Π½Ρ‹Ρ…
      ELSE (
        SELECT
          coalesce(T.list[2] || array_agg(r ORDER BY (r).task_date, (r).id), '{}')
        FROM
          unnest(T.list[3:] || X._r) r
      )
    END
  , X._r
  , X.not_cross
  , T.size + X.not_cross::integer
  FROM
    T
  , LATERAL(
      WITH wrap AS ( -- "ΠΌΠ°Ρ‚Π΅Ρ€ΠΈΠ°Π»ΠΈΠ·ΡƒΠ΅ΠΌ" record
        SELECT
          CASE
            -- Ссли всС-Ρ‚Π°ΠΊΠΈ "ΠΏΠ΅Ρ€Π΅ΡˆΠ°Π³Π½ΡƒΠ»ΠΈ" Ρ‡Π΅Ρ€Π΅Π· 2-ю запись
            WHEN NOT T.not_cross
              -- Ρ‚ΠΎ нуТная запись - пСрвая ΠΈΠ· спписка
              THEN T.list[1]
            ELSE ( -- Ссли Π½Π΅ пСрСсСкли, Ρ‚ΠΎ ΠΊΠ»ΡŽΡ‡ остался ΠΊΠ°ΠΊ Π² ΠΏΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰Π΅ΠΉ записи - отталкиваСмся ΠΎΡ‚ Π½Π΅Π΅
              SELECT
                _r
              FROM
                task _r
              WHERE
                owner_id = (rv).owner_id AND
                (task_date, id) > ((rv).task_date, (rv).id)
              ORDER BY
                task_date, id
              LIMIT 1
            )
          END _r
      )
      SELECT
        _r
      , CASE
          -- Ссли 2-ΠΉ записи ΡƒΠΆΠ΅ Π½Π΅Ρ‚ Π² спискС, Π½ΠΎ ΠΌΡ‹ Ρ…ΠΎΡ‚ΡŒ Ρ‡Ρ‚ΠΎ-Ρ‚ΠΎ нашли
          WHEN list[2] IS NULL AND _r IS DISTINCT FROM NULL THEN
            TRUE
          ELSE -- Π½ΠΈΡ‡Π΅Π³ΠΎ Π½Π΅ нашли ΠΈΠ»ΠΈ "ΠΏΠ΅Ρ€Π΅ΡˆΠ°Π³Π½ΡƒΠ»ΠΈ"
            coalesce(((_r).task_date, (_r).id) < ((list[2]).task_date, (list[2]).id), FALSE)
        END not_cross
      FROM
        wrap
    ) X
  WHERE
    T.size < 20 AND -- ΠΎΠ³Ρ€Π°Π½ΠΈΡ‡ΠΈΠ²Π°Π΅ΠΌ Ρ‚ΡƒΡ‚ количСство
    T.list IS DISTINCT FROM '{}' -- ΠΈΠ»ΠΈ ΠΏΠΎΠΊΠ° список Π½Π΅ кончился
)
-- #3 : "Ρ€Π°Π·Π²ΠΎΡ€Π°Ρ‡ΠΈΠ²Π°Π΅ΠΌ" записи - порядок Π³Π°Ρ€Π°Π½Ρ‚ΠΈΡ€ΠΎΠ²Π°Π½ ΠΏΠΎ ΠΏΠΎΡΡ‚Ρ€ΠΎΠ΅Π½ΠΈΡŽ
SELECT
  (rv).*
FROM
  T
WHERE
  not_cross; -- Π±Π΅Ρ€Π΅ΠΌ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ "Π½Π΅ΠΏΠ΅Ρ€Π΅ΡΠ΅ΠΊΠ°ΡŽΡ‰ΠΈΠ΅" записи

SQL HowTo: Π½Π°ΠΏΠΈΡˆΠ΅Ρ‚Π΅ while-Ρ†ΠΈΠΊΡŠΠ» Π΄ΠΈΡ€Π΅ΠΊΡ‚Π½ΠΎ Π² заявката ΠΈΠ»ΠΈ β€žΠ•Π»Π΅ΠΌΠ΅Π½Ρ‚Π°Ρ€Π½ΠΎ Ρ‚Ρ€ΠΈΠΏΠΎΡΠΎΡ‡Π½ΠΎβ€œ
[Π²ΠΈΠΆΡ‚Π΅ expand.tensor.ru]

По Ρ‚ΠΎΠ·ΠΈ Π½Π°Ρ‡ΠΈΠ½, Π½ΠΈΠ΅ Ρ‚ΡŠΡ€Π³ΡƒΠ²Π°Π½ΠΈ 50% чСтСния Π½Π° Π΄Π°Π½Π½ΠΈ Π·Π° 20% Π²Ρ€Π΅ΠΌΠ΅ Π·Π° изпълнСниС. ВоСст, Π°ΠΊΠΎ ΠΈΠΌΠ°Ρ‚Π΅ ΠΏΡ€ΠΈΡ‡ΠΈΠ½Π° Π΄Π° смятатС, Ρ‡Π΅ Ρ‡Π΅Ρ‚Π΅Π½Π΅Ρ‚ΠΎ ΠΌΠΎΠΆΠ΅ Π΄Π° бъдС дълго (Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€ Π΄Π°Π½Π½ΠΈΡ‚Π΅ чСсто Π½Π΅ са Π² кСша ΠΈ трябва Π΄Π° ΠΎΡ‚ΠΈΠ΄Π΅Ρ‚Π΅ Π½Π° диска Π·Π° Ρ‚ΠΎΠ²Π°), Ρ‚ΠΎΠ³Π°Π²Π° ΠΏΠΎ Ρ‚ΠΎΠ·ΠΈ Π½Π°Ρ‡ΠΈΠ½ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π΄Π° Ρ€Π°Π·Ρ‡ΠΈΡ‚Π°Ρ‚Π΅ Π½Π° ΠΏΠΎ-ΠΌΠ°Π»ΠΊΠΎ Ρ‡Π΅Ρ‚Π΅Π½Π΅.

Π’ΡŠΠ² всСки случай Π²Ρ€Π΅ΠΌΠ΅Ρ‚ΠΎ Π·Π° изпълнСниС сС ΠΎΠΊΠ°Π·Π° ΠΏΠΎ-Π΄ΠΎΠ±Ρ€ΠΎ, ΠΎΡ‚ΠΊΠΎΠ»ΠΊΠΎΡ‚ΠΎ Π² "наивния" ΠΏΡŠΡ€Π²ΠΈ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚. Но коя ΠΎΡ‚ Ρ‚Π΅Π·ΠΈ 3 ΠΎΠΏΡ†ΠΈΠΈ Π΄Π° ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°Ρ‚Π΅, зависи ΠΎΡ‚ вас.

Π˜Π·Ρ‚ΠΎΡ‡Π½ΠΈΠΊ: www.habr.com

ДобавянС Π½Π° Π½ΠΎΠ² ΠΊΠΎΠΌΠ΅Π½Ρ‚Π°Ρ€