Ну, во-первых, было бы хорошо, если бы вы могли объяснить природу ограничений.
Например, может быть разумно, когда кто-то хочет реализовать логику в чистом SQL, но какой в этом смысл?запретить самостоятельные присоединения?Кроме того, вы рассматриваете коррелированные подзапросы из той же таблицы как самостоятельные объединения?А как насчет скалярных подзапросов?
Похоже, вы хотите сделать какой-то трюк с аналитическими (также известными как оконные) функциями, но это невозможно, потому что в этом конкретном случае, потому что вам нужно отслеживать, какие невесты зарезервированыдо сих пор аналитические функции не имеют какого-либо состояния.
Существует два типичных подхода для таких задач, как ваша (когда вы «перебираете» строки и сохраняете некоторое «состояние») в Oracle
- рекурсивный факторинг подзапросов (также известный как рекурсивные CTE)
- предложение модели
Позвольте мне начать с модели, даже если это очень специфическая функция Oracle
SQL> with t as
2 (
3 select *
4 from mytable
5 model
6 dimension by (groom, bride, state)
7 measures (0 reserved)
8 (
9 reserved[any,any,any] order by groom, bride, state
10 = case
11 -- current groom already has a bride
12 when max(reserved)[cv(groom), lnnvl(bride > cv(bride)), any] = 1
13 -- current bride already reserved for some groom
14 or max(reserved)[groom < cv(groom), cv(bride), any] = 1
15 then 0 else 1
16 end
17 )
18 )
19 select groom, bride, state
20 from t
21 where reserved = 1
22 union all
23 select groom, null, min(state)
24 from mytable
25 where groom not in (select groom from t where reserved = 1)
26 group by groom
27 order by 1;
GROOM BRIDE STATE
---------- ---------- ----------
ALVIN CARMEN NJ
CARL ELEANOR AL
DAVID DIANA NE
FRANK NV
MIKE RI
В этом решении столбец reserved
используется для обозначения каждой строки, в которой «выделена» невеста.Подход работает только в Oracle, начиная с версии 10g Release 1, когда впервые было введено предложение модели.
Второе решение ниже
SQL> with rec(groom, bride, state, reserved)
2 as (select min(groom),
3 min(bride) keep (dense_rank first order by groom),
4 min(state) keep (dense_rank first order by groom, bride),
5 min(bride) keep (dense_rank first order by groom)
6 from mytable
7 union all
8 select t.groom,
9 t.bride,
10 t.state,
11 r.reserved || '#' || t.bride
12 from rec r
13 cross apply
14 (select min(groom) groom,
15 min(bride) keep (dense_rank first order by groom) bride,
16 min(state) keep (dense_rank first order by groom, bride) state
17 from mytable
18 where groom > r.groom and instr(r.reserved, bride) = 0) t
19 where t.groom is not null)
20 cycle groom set c to 1 default 0
21 select groom, bride, state
22 from rec
23 union all
24 select groom, null, min(state)
25 from mytable
26 where groom not in (select groom from rec)
27 group by groom
28 order by 1;
GROOM BRIDE STATE
---------- ---------- ----------
ALVIN CARMEN NJ
CARL ELEANOR AL
DAVID DIANA NE
FRANK NV
MIKE RI
В этом решении вы можете избавиться от определенной функции Oracle keep dense_rank
и избегайте использования cross apply
, который был введен только в 12c.Также вы можете отслеживать зарезервированные невесты, используя коллекцию вместо объединенной строки, но ... опять же, это решение для Oracle.
Однако, это (с небольшими изменениями) может быть принято, скажем, на SQL-сервере.
PS.
Говоря о производительности, рекурсивное решение сканирует весь mytable во время каждого выполнения рекурсивного члена, что делает его нежизнеспособным для любого относительно большого набора данных.
model
может быть хорошо, скажем, на тысячах строк, но все же он вычисляет агрегаты (max(reserved)
) для каждой строки, чего можно избежать в подходе, отличном от SQL.