powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Firebird, InterBase [игнор отключен] [закрыт для гостей] / Простановка в FK-поле дочерней таблицы случайного значения из родителя
9 сообщений из 9, страница 1 из 1
Простановка в FK-поле дочерней таблицы случайного значения из родителя
    #38582073
Таблоид
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Пфф... родилось-таки одним запросом, хоть и в муках...
Запишу сюда на память, но может и кому еще пригодится.

DDL : depts = таблица участков (родительская) и users = таблица сотрудников. Таблица сотрудников имеет поле-ссылку на участки, но оно в первоначальном скрипте = null.
Требуется заполнить это поле случайными id'шниками из родительской таблицы, используя rand():
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
recreate table depts(id int primary key, name not null unique); commit;
insert into depts values(11, 'sales');
insert into depts values(101, 'logistics');
insert into depts values(1001, 'IT');
insert into depts values(101001, 'administration');
insert into depts values(1010101, 'HR');
commit;
recreate table users(
    id int primary key,
    dept_id int,
    name unique,
    constraint users_fk foreign key (id) references depts(id) );
commit;
insert into users(id, name) select row_number()over(),'user #'||row_number()over()
from rdb$types;
commit;


update-команда получилась вот такой:
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
update users
set dept_id =
(
    select d.id
    from ( select id, row_number()over() rn from depts ) d
    join( select cast(round((0.5+rand()*(select count(*) from depts)),0) as int) rx from depts ) b
    on d.rn = b.rx
    rows 1
);

Проверочный запрос для показа перекосов (если они есть):
Код: sql
1.
select u.dept_id, count(*) c, 1.0000*count(*)/count(*)over() d  from users u group by 1

(во всех строках значения в столбце 'd' должны быть близкими друг к другу).

PS. Без материализации рандомов как-то тоскливо... :'(
...
Рейтинг: 0 / 0
Простановка в FK-поле дочерней таблицы случайного значения из родителя
    #38582129
Гхостик
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Напиши один раз и используй повторно.

create global temporary table gtt_random (value integer not nul primary key);
create procedure fill_randoms(max_value number; count integer);

Еще можно процедуру для нормального распределения сделать.
...
Рейтинг: 0 / 0
Простановка в FK-поле дочерней таблицы случайного значения из родителя
    #38582158
Таблоид
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ГхостикНапиши один раз и используй повторно.

create global temporary table gtt_random (value integer not nul primary key);
create procedure fill_randoms(max_value number; count integer);

Еще можно процедуру для нормального распределения сделать.Не интересно, ибо процедурно. Да и под каждый случай одной такой gtt_random + fill_randoms не напасёшься.
Кстати, зачем делать процедуру для нормального распр-я, когда rand() как раз и даёт его ?
...
Рейтинг: 0 / 0
Простановка в FK-поле дочерней таблицы случайного значения из родителя
    #38582163
Гхостик
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Зачем под каждый случай свою? Задаешь в параметрах процедуры количество записей и джойнишь gtt к результату по номеру записи из нужной таблицы.

Нормальное в математическом смысле, rand дает равномерное (тоже в математическом ).
...
Рейтинг: 0 / 0
Простановка в FK-поле дочерней таблицы случайного значения из родителя
    #38582174
Таблоид
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Гхостикджойнишь gtt к результату по номеру записи из нужной таблицы.на примере покажи, плз. Что-то " номер записи" заинтересовал (если это не row_number()over(), конечно же).
...
Рейтинг: 0 / 0
Простановка в FK-поле дочерней таблицы случайного значения из родителя
    #38582195
Гхостик
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Таблоидесли это не row_number()over(), конечно жеОн самый и есть. Но вообще, конечно, выгода мизерная получается.

Лучше, наверное, вот этот кусок переделать на динамический sql в процедуре по названию таблицы.

Код: sql
1.
2.
3.
4.
5.
select d.id
    from ( select id, row_number()over() rn from depts ) d
    join( select cast(round((0.5+rand()*(select count(*) from depts)),0) as int) rx from depts ) b
    on d.rn = b.rx
    rows 1

Кстати, зачем в "b" из depts запрашивается? Нужна же только одна запись, можно и из rdb$database.
...
Рейтинг: 0 / 0
Простановка в FK-поле дочерней таблицы случайного значения из родителя
    #38582207
Таблоид
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ГхостикКстати, зачем в "b" из depts запрашивается? Нужна же только одна запись, можно и из rdb$database.да, ты прав. Это я в пылу "борьбы за идею" упустил :-)
Вот так правильнее:
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
update users
set dept_id =
(
    select d.id
    from ( select id, row_number()over() rn from depts ) d
    join( select cast(round((0.5+rand()*(select count(*) from depts)),0) as int) rx from rdb$database ) b
    on d.rn = b.rx
);
...
Рейтинг: 0 / 0
Простановка в FK-поле дочерней таблицы случайного значения из родителя
    #38585912
afgm
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Таблоид,

Через GTT будет работать неплохо. Особенно если ID-шники это чаще всего integer.
Есть вариант использовать скроллируемые курсоры. Они довольно шустры. Не одним запросом, но зато без GTT и реально быстро.

Записей в таблицах
users: 63001
depts: 5

Предлагаемый update:
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
update users
set dept_id =
(
    select d.id
    from ( select id, row_number()over() rn from depts ) d
    join( select cast(round((0.5+rand()*(select count(*) from depts)),0) as int) rx from rdb$database ) b
    on d.rn = b.rx
);
-- Execute time = 3s 432ms


Просто update:
Код: sql
1.
2.
3.
update users
set dept_id = 11
--Execute time = 1s 185ms


Через курсоры:
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
execute block as
declare cur scroll cursor for (select d.id from depts d);
declare depts_cnt integer;
declare id integer;
declare dept_id integer;
begin
  select count(*) from depts d into :depts_cnt;
  open cur;
  for select u.id from users u
  into :id
  as cursor tmp_cursor
  do
  begin
    fetch absolute round(0.5+rand()*:depts_cnt) from cur into :dept_id;
    update users set dept_id = :dept_id where current of tmp_cursor;
  end
 close cur;
end
-- Execute time = 1s 404ms


При количестве записей в depts 10000: Execute time = 1s 591ms

Чуть более корректный запрос оценки распределения:
Код: sql
1.
2.
3.
select d.id as dept_id, count(u.dept_id) as cnt_all, 1.0000*count(u.dept_id)/count(*)over() as cnt_dept from depts d
    left join users u on u.dept_id = d.id
group by d.id
...
Рейтинг: 0 / 0
Простановка в FK-поле дочерней таблицы случайного значения из родителя
    #38586256
Таблоид
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
afgmЧерез курсорыЗаинтриговал. Проверю попозже, спасибо за идею.
...
Рейтинг: 0 / 0
9 сообщений из 9, страница 1 из 1
Форумы / Firebird, InterBase [игнор отключен] [закрыт для гостей] / Простановка в FK-поле дочерней таблицы случайного значения из родителя
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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