Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / MySQL [игнор отключен] [закрыт для гостей] / рекурсивная функция (процедура) / 25 сообщений из 43, страница 1 из 2
08.05.2008, 07:19:19
    #35301291
djvov
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
рекурсивная функция (процедура)
Доброго времени суток вам!
Насколько я понял, рекурсию простым запросом не реализовать, и надо писать хранимую процедуру(функцию) для этого. В этом и прошу собственно у вас помощи.
Древовидная структура, поля id и top отвечают за дерево, есть некое поле isgroup.
так вот, надо посчитать количество записей, у которых isgroup равно 3, начиная от указанного id вглубь дерева
маленький пример
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
id	name 		top	isgroup
------------------------------------
1	самосвалы		0	1
2	катки		0	1
3	большие		1	1
4	средние		1	1
5	малые		1	1
6	фото1		3	3
7	фото2		4	3
8	фото3		5	3
То есть, если применить эту функцию к самосвалам, вернуть надо 3 (3 фотки), если к большим, средним или малым, то 1.
...
Рейтинг: 0 / 0
08.05.2008, 09:41:19
    #35301506
javajdbc
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
рекурсивная функция (процедура)
хорошо бы глубина груп была бы небольшая фиксированая.
Что-то типа:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
select id, name, count( 1 ) cnt
from (
select id, name, t1.isgroup t1g, t2.isgroup t2g, t3.isgroup t3g, t4.isgroup t4g
from
tbl t1 left join tbl t2 on t1.id = t2.top
        left join tbl t3 on t2.id = t3.top
        left join tbl t4 on t3.id = t4.top ) x
where 
  (t1g= 3 ) or (t2g= 3 ) or (t3g= 3 ) or (t4g= 3 )  -- 3 in (t1g,t2g,t3g,t4g)
group by id  
...
Рейтинг: 0 / 0
08.05.2008, 10:58:29
    #35301758
djvov
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
рекурсивная функция (процедура)
не, каталог бесконечный ваще
...
Рейтинг: 0 / 0
08.05.2008, 11:50:25
    #35301984
skol
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
рекурсивная функция (процедура)
Код: plaintext
1.
2.
create function getPicturesCount(aID bigint) returns bigint
return (select sum(isgroup= 3 ) + sum(getPicturesCount(id)) from TABLE1 where top = aID);
...
Рейтинг: 0 / 0
08.05.2008, 12:05:36
    #35302057
djvov
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
рекурсивная функция (процедура)
спасибо, но при попытке сделать
Код: plaintext
select getPicturesCount( 100695 );
выдало ошибку 1424: recursive stored function and triggers are not allowed.
может прав не хватает у юзера? или в функции дело?
...
Рейтинг: 0 / 0
08.05.2008, 12:20:35
    #35302129
djvov
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
рекурсивная функция (процедура)
хотя у себя из под рута выполнил, прав навалом, то же самое сказал
...
Рейтинг: 0 / 0
08.05.2008, 12:29:35
    #35302160
Nick Anikin
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
рекурсивная функция (процедура)
рекурсивно процедуру нельзя вызывать в mysql, делайте через цикл
...
Рейтинг: 0 / 0
08.05.2008, 12:34:23
    #35302178
djvov
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
рекурсивная функция (процедура)
пожалуйста поясните, как, немного в мускуле понимаю
...
Рейтинг: 0 / 0
08.05.2008, 12:35:41
    #35302181
Nick Anikin
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
рекурсивная функция (процедура)
что как? цикл написать?
http://dev.mysql.com/doc/refman/5.0/en/while-statement.html
...
Рейтинг: 0 / 0
08.05.2008, 13:30:15
    #35302378
djvov
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
рекурсивная функция (процедура)
я думал эту функцию как то по другому запустить.
смысл писать тогда рекурсивные функции, если их нельзя запускать..
...
Рейтинг: 0 / 0
08.05.2008, 13:35:09
    #35302389
xelaok
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
рекурсивная функция (процедура)
Nick Anikinрекурсивно процедуру нельзя вызывать в mysql, делайте через цикл
Можно
...
Рейтинг: 0 / 0
08.05.2008, 13:39:34
    #35302405
djvov
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
рекурсивная функция (процедура)
xelaok Nick Anikinрекурсивно процедуру нельзя вызывать в mysql, делайте через цикл
Можно
помогите уже )))
...
Рейтинг: 0 / 0
08.05.2008, 13:45:26
    #35302424
xelaok
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
рекурсивная функция (процедура)
djvov xelaok Nick Anikinрекурсивно процедуру нельзя вызывать в mysql, делайте через цикл
Можно
помогите уже )))
Через процедуру делай
...
Рейтинг: 0 / 0
08.05.2008, 13:57:37
    #35302459
djvov
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
рекурсивная функция (процедура)
Код: plaintext
1.
2.
CREATE FUNCTION `getPicturesCount`(aID bigint) RETURNS bigint( 20 )
return (select sum(isgroup= 3 ) + sum(getPicturesCount(id)) from foto_foto where top = aID);
function заменить на procedure?
...
Рейтинг: 0 / 0
08.05.2008, 14:26:51
    #35302555
xelaok
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
рекурсивная функция (процедура)
djvov
Код: plaintext
1.
2.
CREATE FUNCTION `getPicturesCount`(aID bigint) RETURNS bigint( 20 )
return (select sum(isgroup= 3 ) + sum(getPicturesCount(id)) from foto_foto where top = aID);
function заменить на procedure?
хз, у меня тока так получилось:
Код: 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.
29.
30.
31.
32.
33.
34.
35.
36.
drop procedure if exists go;
drop function if exists calc;

delimiter |

create procedure go(p_id int, p_isgroup int, in k1 int, out k2 int)
begin
  declare done, l_id, l_isgroup int default  0 ;
  declare cur cursor for 
    select
      id,
      isgroup
    from
      foto_foto
    where
      top = p_id;
  declare continue handler for sqlstate '02000' set done =  1 ;

  set k2 = k1;
  open cur;
    repeat
      fetch cur into l_id, l_isgroup;
      if not done then
        call go(l_id, p_isgroup, k2 + if(l_isgroup = p_isgroup,  1 ,  0 ), k2);
      end if;
    until done end repeat;
  close cur;
end
|

create function calc(p_id int, p_isgroup int) returns int
begin
  declare k int default  0 ;
  call go(p_id, p_isgroup, k, k);
  return k;
end
Код: plaintext
select calc( 1 ,  3 )
...
Рейтинг: 0 / 0
08.05.2008, 14:44:37
    #35302628
MAPA3OT
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
рекурсивная функция (процедура)
Попрошу кинуть в меня камнем за этот вариант.
Перед тем как ловить камень поясню, рекурсия имеет обыкновение падать при определенном уровне вложенности, а этому абсолютно пофиг.

Код: 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.
delimiter //
create FUNCTION `selectSomething`(recPID INT, recType INT) RETURNS bigint( 20 )
BEGIN
  DECLARE ids BLOB;
  DECLARE tempIDScount INT;
  DECLARE IDScount INT;
  set tempIDScount =  0 ;
  select group_concat(t.id), count(t.id) into ids, IDScount 
	from temptab t 
	where t.top = recPID or t.id=recPID;

	WHILE tempIDScount < IDScount DO
  	set tempIDScount = IDScount;
    select 
			group_concat(t.id), count(t.id) into ids, IDScount
		from 
			temptab t
		where 
			FIND_IN_SET(t.id,ids)	>  0 
			OR FIND_IN_SET(t.top,ids) > 0 ;
  END WHILE;
  return (select count(*) from tempTab where
	FIND_IN_SET(ID,ids)	>  0  and isGroup=recType);						
	
END//
delimiter ;
...
Рейтинг: 0 / 0
08.05.2008, 15:14:26
    #35302734
Nick Anikin
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
рекурсивная функция (процедура)
MAPA3OTПопрошу кинуть в меня камнем за этот вариант.зачем же камнем? я сразу написал - лучше через цикл переделать :)
MAPA3OTПеред тем как ловить камень поясню, рекурсия имеет обыкновение падать при определенном уровне вложенности, а этому абсолютно пофиг.в mysql даже специальный параметр есть - max_sp_recursion_depth
...
Рейтинг: 0 / 0
08.05.2008, 15:15:13
    #35302737
Nick Anikin
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
рекурсивная функция (процедура)
xelaok Nick Anikinрекурсивно процедуру нельзя вызывать в mysql, делайте через цикл
Можнода, я неправильно написал, имел ввиду функцию - как хотел автор
...
Рейтинг: 0 / 0
08.05.2008, 15:22:11
    #35302762
djvov
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
рекурсивная функция (процедура)
вообщем скрипт Nick Anikin выдал что Recursive limit 0 (as set by max_sp_recursion_depth variable) was exceeded by routine go
max_sp_recursion_depth надо увеличить? как его указать явно?
Код: plaintext
set @max_sp_recursion_depth= 3000 ;
перед выполнением - не помогло
скрипт MAPA3OT'a на небольшой вложенности работает верно, а на большой - нет.
В архиве дамп базы.
Если считать фотки экскаваторов
Код: plaintext
select selectSomething( 100695 , 3 );
, то будет 13, это верно.
А если считать самосвалы
Код: plaintext
select selectSomething( 100693 , 3 );
, то будет 133, хотя на самом деле там 248.
...
Рейтинг: 0 / 0
08.05.2008, 15:28:56
    #35302784
MAPA3OT
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
рекурсивная функция (процедура)
Nick Anikinв mysql даже специальный параметр есть - max_sp_recursion_depth
Все равно есть максимальное ограничение (255), после которого даже изменение этого параметра не спасет. Опять-таки, если нас устроит некое значение в пределах от 0 до 255, то мы ткнемся в некое подобие этого:
Код: plaintext
1.
2.
ERROR  1436  (HY000): Thread stack overrun:   180628  bytes used of a  262144  byte stack, and
 81920  bytes needed.  Use 'mysqld -O thread_stack=#' to specify a bigger stack.
И будем долго с бубном подбирать нужное значение, поэтому я подумал и послал к черту скорость ради спасения собственных нервов.
...
Рейтинг: 0 / 0
08.05.2008, 15:34:00
    #35302796
djvov
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
рекурсивная функция (процедура)
даже твой скрипт работает быстрей чем та же рекурсия на пхп. еще бы верно посчитала
...
Рейтинг: 0 / 0
08.05.2008, 15:37:16
    #35302804
skol
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
рекурсивная функция (процедура)
MAPA3OTПопрошу кинуть в меня камнем за этот вариант.
Перед тем как ловить камень поясню, рекурсия имеет обыкновение падать при определенном уровне вложенности, а этому абсолютно пофиг.


Минус один - многократный фуллскан таблицы (по числу вложенных уровней), т.е. тормоза
...
как вариант:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
delimiter //
create FUNCTION `selectSomething`(recPID INT, recType INT) RETURNS bigint( 20 )
BEGIN
  DECLARE ids BLOB;
  DECLARE result INT;
  DECLARE childs BLOB;
  DECLARE currentPID char;
  set ids = concat(recPID,',');
  set result =  0 ;
  while length(ids) do
    set currentPID = substring_index(ids,',', 1 );
    set ids = substring(ids,length(currentPID)+ 2 );
    select group_concat(t.id), sum(isGroup=recType) + result into childs, result
	from temptab t 
	where t.top = currentPID;
    if length(childs) >  0  then
      set ids = concat(ids,childs,',');
    end if;
  end while;
  return result;						
END//
delimiter ;
здесь у нас запросы в цикле будут индексированными (при наличии индекса на top), и для каждого ид будут выполнены 1 раз
...
Рейтинг: 0 / 0
08.05.2008, 15:52:16
    #35302848
djvov
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
рекурсивная функция (процедура)
skol, повис мускуль, 99 процентов нагрузки на камень
...
Рейтинг: 0 / 0
08.05.2008, 16:09:59
    #35302899
xelaok
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
рекурсивная функция (процедура)
djvov, индекс на top установи
...
Рейтинг: 0 / 0
08.05.2008, 16:13:10
    #35302912
djvov
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
рекурсивная функция (процедура)
дак поставил перед тем как выполнить
...
Рейтинг: 0 / 0
Форумы / MySQL [игнор отключен] [закрыт для гостей] / рекурсивная функция (процедура) / 25 сообщений из 43, страница 1 из 2
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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