powered by simpleCommunicator - 2.0.49     © 2025 Programmizd 02
Форумы / Firebird, InterBase [игнор отключен] [закрыт для гостей] / Как соорудить record set из N строк?
25 сообщений из 25, страница 1 из 1
Как соорудить record set из N строк?
    #40007848
shalamyansky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Есть произвольное число N. Нужно с помощью select получить record set из N записей, поля не важны:

null
null
...
null

Хранимые процедуры не использовать, с ними все понятно. Должно быть что-то вроде такого

Код: sql
1.
2.
3.
4.
5.
select
  first ( :N )
    null
  from
    X



где X - таблица с числом записей, заведомо большим N. Но такой таблицы X нет, а N может быть произвольно большим.

Чисто игра ума.
...
Рейтинг: 0 / 0
Как соорудить record set из N строк?
    #40007852
ъъъъъ
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
shalamyansky,

execute block - тоже нельзя?
...
Рейтинг: 0 / 0
Как соорудить record set из N строк?
    #40007854
hvlad
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
shalamyansky
Чисто игра ум
with recursive
...
Рейтинг: 0 / 0
Как соорудить record set из N строк?
    #40007859
Dimbuch®
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Код: plsql
1.
2.
3.
4.
5.
6.
WITH RECURSIVE r(n) AS (
SELECT 1 FROM rdb$database
UNION ALL
SELECT n+1 FROM r where n < 100
)
select * from r
...
Рейтинг: 0 / 0
Как соорудить record set из N строк?
    #40007863
shalamyansky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
execute block... это, возможно, решение, если смотреть практически. А из PSQL тоже можно вызывать execute block, и for execute block делать?

Но это не очень интересное решение, просто обход запрета на хранимую процедуру. Давайте предположим, что нельзя.
...
Рейтинг: 0 / 0
Как соорудить record set из N строк?
    #40007864
shalamyansky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dimbuch®

Код: plsql
1.
2.
3.
4.
5.
6.
WITH RECURSIVE r(n) AS (
SELECT 1 FROM rdb$database
UNION ALL
SELECT n+1 FROM r where n < 100
)
select * from r




Класс! Все решается, однако. Даже не подумал в сторону RECURSIVE.

Спасибо!
...
Рейтинг: 0 / 0
Как соорудить record set из N строк?
    #40007865
ъъъъъ
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Dimbuch®
Код: plsql
1.
2.
3.
4.
5.
6.
WITH RECURSIVE r(n) AS (
SELECT 1 FROM rdb$database
UNION ALL
SELECT n+1 FROM r where n < 100
)
select * from r


Классно.
...
Рейтинг: 0 / 0
Как соорудить record set из N строк?
    #40007875
shalamyansky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dimbuch®
Код: plsql
1.
2.
3.
4.
5.
6.
WITH RECURSIVE r(n) AS (
SELECT 1 FROM rdb$database
UNION ALL
SELECT n+1 FROM r where n < 100
)
select * from r



Только вот как реализована эта рекурсия сервером? При N порядка миллиона-миллиарда не лопнет ли у него стек?
...
Рейтинг: 0 / 0
Как соорудить record set из N строк?
    #40007878
Фотография Симонов Денис
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
shalamyansky,

глубина рекурсии ограничена 1023 уровнями. Если надо генерировать числа больше 1000 можно использовать r cross join r
...
Рейтинг: 0 / 0
Как соорудить record set из N строк?
    #40007879
shalamyansky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Симонов Денис

глубина рекурсии ограничена 1023 уровнями. Если надо генерировать числа больше 1000 можно использовать r cross join r

Да... уже увидел. А жаль. Возводить r в степень не так красиво. Но можно, 2 раза cross join - уже миллиард.
...
Рейтинг: 0 / 0
Как соорудить record set из N строк?
    #40007880
Dimbuch®
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Отдельно запрос все равно не нужен. Он будет в процедуре скорее всего. Ну или в EXECUTE BLOCK.

Тогда вставить эту конструкцию целиком в WHILE ..
И подставлять вместо начальной единицы переменную.
Выводить записи через SUSPEND или в таблицу.

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
While I<1000000 do
Begin
For
WITH RECURSIVE r(n) AS (
SELECT :I FROM rdb$database
UNION ALL
SELECT n+1 FROM r where n < 1000
) 
select r.n from r
Into :v_num
Do
  Suspend;

I = I + 1000;
End



Получится почти бесконечная последовательность


Ну или как сказали через CROSS JOIN
...
Рейтинг: 0 / 0
Как соорудить record set из N строк?
    #40007881
shalamyansky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Не, ну если в руках есть while и suspend, то вопросов вообще нет :)

Код: sql
1.
2.
3.
4.
5.
:I = 0;
while( I <= 10000000 )do begin
    :I = :I + 1;
    suspend;
end
...
Рейтинг: 0 / 0
Как соорудить record set из N строк?
    #40007882
Dimbuch®
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
shalamyansky,

Просто WHILE не сджоинить с каким-нибудь набором записей. Только по одной получится.


Например можно сгенерить таблицу с датами каждый час за весь месяц. И соединить с событиями.
В обычном while придётся искать по одной за одну итерацию
...
Рейтинг: 0 / 0
Как соорудить record set из N строк?
    #40007887
shalamyansky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dimbuch®

Просто WHILE не сджоинить с каким-нибудь набором записей

ИМХО можно как-нибудь проще, чем через рекурсию. Но это мы далеко отклонились от темы.

Вопрос был - как получить искомое в рамках SQL, но не PSQL. Вы дали красивое решение, но оно увы, имеет сильное ограничение. Денис и Вы подсказали, как его можно расширить через cross join. Да, наверное, так и надо.
...
Рейтинг: 0 / 0
Как соорудить record set из N строк?
    #40007969
Ivan_Pisarevsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
shalamyansky
Вопрос был - как получить искомое в рамках SQL
не проще создать один раз таблицу на макс требуемое число и джойниться с ней? create table NN(n integer);

... join NN on n<100
...
Рейтинг: 0 / 0
Как соорудить record set из N строк?
    #40007970
Фотография Exteris
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
А рекурсию внутри рекурсии можно?
...
Рейтинг: 0 / 0
Как соорудить record set из N строк?
    #40007976
Фотография Exteris
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Проверил, нельзя.
WITH clause can't be nested.
...
Рейтинг: 0 / 0
Как соорудить record set из N строк?
    #40007990
hvlad
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Exteris
А рекурсию внутри рекурсии можно?
Нет смысла
...
Рейтинг: 0 / 0
Как соорудить record set из N строк?
    #40008010
Фотография Симонов Денис
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
shalamyansky,

там есть одна хитрость. CROSS JOIN заставит выполнять рекурсивный запрос каждый раз. Это несколько дорого, поэтому можно придумать искусственный трюк, так чтобы выполнялся HASH JOIN. Например в данном запросе для генерации миллиарда записей рекусрсивный запрос будет выполнен всего три раза вместо миллиона

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
with recursive r as (
  select 0 as n, 1 as k from rdb$database
  union all
  select n + 1, 1 as k from r where n < 999
),
t as (
select
  r1.n + r2.n * 1000 + r3.n * 1000000 as n
from r r1
join r r2 on r2.k = r1.k
join r r3 on r3.k = r1.k)
select count(*) from t



Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
План
PLAN HASH (T R RDB$DATABASE NATURAL, , T R RDB$DATABASE NATURAL, , T R RDB$DATABASE NATURAL, )

Select Expression
    -> Aggregate
        -> Filter
            -> Hash Join (inner)
                -> Recursion
                    -> Table "RDB$DATABASE" as "T R RDB$DATABASE" Full Scan
                    -> Filter
                -> Record Buffer (record length: 41)
                    -> Recursion
                        -> Table "RDB$DATABASE" as "T R RDB$DATABASE" Full Scan
                        -> Filter
                -> Record Buffer (record length: 41)
                    -> Recursion
                        -> Table "RDB$DATABASE" as "T R RDB$DATABASE" Full Scan


------ Информация о производительности ------
Время подготовки запроса = 0ms
Время выполнения запроса = 5m 6s 620ms
Среднее время на получение одной записи = 306 620,00 ms
Current memory = 280 101 824
Max memory = 1 354 265 088
Memory buffers = 16 384
Reads from disk to cache = 0
Writes from cache to disk = 0
Чтений из кэша = 21

Обрати внимание, потребовался всего 21 фетч

а вот кросс джойном

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
with recursive r as (
  select 0 as n, 1 as k from rdb$database
  union all
  select n + 1, 1 as k from r where n < 999
),
t as (
select
  r1.n + r2.n * 1000 + r3.n * 1000000 as n
from r r1
cross join r r2
cross join r r3 
)
select count(*) from t



Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
План
PLAN JOIN (T R RDB$DATABASE NATURAL, , T R RDB$DATABASE NATURAL, , T R RDB$DATABASE NATURAL, )

elect Expression
    -> Aggregate
        -> Nested Loop Join (inner)
            -> Recursion
                -> Table "RDB$DATABASE" as "T R RDB$DATABASE" Full Scan
                -> Filter
            -> Recursion
                -> Table "RDB$DATABASE" as "T R RDB$DATABASE" Full Scan
                -> Filter
            -> Recursion
                -> Table "RDB$DATABASE" as "T R RDB$DATABASE" Full Scan
                -> Filter

------ Информация о производительности ------
Время подготовки запроса = 16ms
Время выполнения запроса = 8m 58s 438ms
Среднее время на получение одной записи = 538 438,00 ms
Current memory = 280 109 456
Max memory = 280 921 808
Memory buffers = 16 384
Reads from disk to cache = 0
Writes from cache to disk = 0
Чтений из кэша = 5 005 011
...
Рейтинг: 0 / 0
Как соорудить record set из N строк?
    #40008022
hvlad
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Симонов Денис,

Max memory заодно сравни, нужно учитывать все факторы
...
Рейтинг: 0 / 0
Как соорудить record set из N строк?
    #40008027
Фотография Симонов Денис
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
hvlad,

ага сразу не обратил внимание. Но время получилось лучше.
Хотя для большого количества пользователей, лучше память экономить
...
Рейтинг: 0 / 0
Как соорудить record set из N строк?
    #40008169
shalamyansky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Симонов Денис

поэтому можно придумать искусственный трюк, так чтобы выполнялся HASH JOIN.

Хитро. Не очень соображаю, почему так получается, но это повод для подумать. Спасибо!
...
Рейтинг: 0 / 0
Как соорудить record set из N строк?
    #40008388
WildSery
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Я думал, вы отшутились и всё на этом. А вы на полном серьёзе...

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
with c as (
select 0 cnt from rdb$database
union all select 1 from rdb$database
union all select 2 from rdb$database
union all select 3 from rdb$database
union all select 4 from rdb$database
union all select 5 from rdb$database
union all select 6 from rdb$database
union all select 7 from rdb$database
union all select 8 from rdb$database
union all select 9 from rdb$database
),
cc as (select c1.cnt + c2.cnt*10 + c3.cnt*100 as cnt
  from c as c1, c as c2, c as c3
)
select c1.cnt + c2.cnt*1000
  from cc as c1, cc as c2
order by 1
...
Рейтинг: 0 / 0
Как соорудить record set из N строк?
    #40008573
shalamyansky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Логично. Тогда уж вот так, чтобы без лишней пересортировки:

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
with c as (
            select 0 d from rdb$database
  union all select 1 d from rdb$database
  union all select 2 d from rdb$database
  union all select 3 d from rdb$database
  union all select 4 d from rdb$database
  union all select 5 d from rdb$database
  union all select 6 d from rdb$database
  union all select 7 d from rdb$database
  union all select 8 d from rdb$database
  union all select 9 d from rdb$database
)
select
  first( :N )
       c0.d * 1000000000
    +  c1.d * 0100000000
    +  c2.d * 0010000000
    +  c3.d * 0001000000
    +  c4.d * 0000100000
    +  c5.d * 0000010000
    +  c6.d * 0000001000
    +  c7.d * 0000000100
    +  c8.d * 0000000010
    +  c9.d * 0000000001
  from
      c as c0
    , c as c1
    , c as c2
    , c as c3
    , c as c4
    , c as c5
    , c as c6
    , c as c7
    , c as c8
    , c as c9
;
--order by 1



Спасибо!
...
Рейтинг: 0 / 0
Как соорудить record set из N строк?
    #40008779
Агрох
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Можно "обмануть" ограничение рекурсии:
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
WITH recursive R0 AS (
SELECT 1 AS N1, 1 AS N2 FROM RDB$DATABASE
UNION ALL
SELECT N1 + 1 AS N1, N2 FROM R0 WHERE N1 < 10
UNION ALL
SELECT N1, N2 + 1 AS N2 FROM R0 WHERE N2 < 10
)
SELECT N1 FROM R0
UNION ALL
SELECT N2 AS N1 FROM R0;



В данном случае запрос уже вернёт 369510 строк, что как бы существенно выше ограничения на глубину рекурсий. А всё дело в том, что в данном случае формируется обрезанное бинарное дерево (обрезанное, потому что не из всех узлов выходят новые ветки) и рекурсия ограничена глубиной этого дерева - в данном случае глубина всего на всего 10. Ставить 1023 вместо 10 не рекомендую. Да, сервер это съест но значений будет всё же слишком много. Даже 20 не советую. Сервер будет, мягко говоря, очень долго вычислять результат. :)

Вот так сходу вывести математическую формулу, зависимости N от глубины дерева, чтобы однозначно решить задачу, я не готов.
А ведь можно ещё добавить третье поле и третий UNION... И четвёртое поле с четвёртым UNION-ом.... Ну вы поняли...
...
Рейтинг: 0 / 0
25 сообщений из 25, страница 1 из 1
Форумы / Firebird, InterBase [игнор отключен] [закрыт для гостей] / Как соорудить record set из N строк?
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]