BULK COLLECTIONS - чего это такое ?

ABORIGEN

Guest
BULK COLLECTIONS - чего это такое ?

Парни, бьюсь тут над постраничным выводом из ORACLE. Естессно, перечитал весь топик на эту тему. Решение с вложенными запросами мне совсем не нравится ... но вот мелькнуло всего один раз что-то про BULK COLLECT и очень красивое решение для постраничногов вывода с LIMIT X, Y !

Кто пользовал такое решение - расскажите, пожалуста ! :) Поделитесь опытом.
 

romutis

Guest
Ну я пользую периодически BULK COLLECTIONS - с связке PL/SQL + Java.
Поддерживает PHP работу с BULK COLLECTION напрямую или нет - я не знаю. Если не поддерживает - приготовься к извратам типа динамического SQL или преобразования данных уже на уровне PHP.
 

ABORIGEN

Guest
Так что же есть эти балк коллекции ? Java-класс ? Конструкция PL/SQL ?
 

romutis

Guest
PL/SQL конструкция.

Здесь хорошо описано: http://download-west.oracle.com/docs/cd/B10501_01/appdev.920/a96624/05_colls.htm
 

ABORIGEN

Guest
Спасибо конечно, понятно, что надо разбираться :)
 

ABORIGEN

Guest
А может кто делал постраничный вывод с помощью BULK COLLECTIONS из PHP ???
 

Rezec

По пиву? (socket80)
Немножко кода :)
PHP:
PROCEDURE xxx(		
	pi_current 	IN INTEGER, --dannaja stranica
	pi_per_page 	IN INTEGER, --kol-vo na str	
	pi_order 	IN VARCHAR2, --asc or desc  
	po_found	OUT INTEGER,
	mycurs 	OUT TYPES.cursorType
)
	IS
BEGIN
	SELECT	COUNT(*)
	INTO 	po_found		
	FROM	TABLE
	WHERE	xxx;		

	
	OPEN mycurs FOR
	SELECT * FROM(
		SELECT	ROWNUM num_id, --!
			TABLE.*
		FROM	TABLE
		
                 )
	WHERE	num_id >= NAVIGATION('start',pi_order,pi_current,pi_per_page,po_found)
	AND	num_id <= NAVIGATION('end',pi_order,pi_current,pi_per_page,po_found) 
	 ;
 

END; -- Procedure

FUNCTION NAVIGATION(
	pi_type		IN VARCHAR2, -- 'start'||'end'
	pi_order	IN VARCHAR2, -- desc||asc
	pi_current 	IN INTEGER,	
	pi_per_page 	IN INTEGER,
	pi_found	in integer

)
  RETURN  INTEGER IS
	end_r INTEGER;
	start_r INTEGER;
	p_current INTEGER;
	p_max INTEGER;
BEGIN 
if(pi_order = 'desc')then	
	p_max := CEIL(pi_found/pi_per_page);	
	IF(pi_current = 0)THEN
		p_current := p_max;	
		else
		p_current := pi_current;
	END IF;	
	
	IF(p_current = p_max) THEN
		end_r := pi_found;
	ELSE
		end_r := pi_found-(pi_per_page*(p_max-p_current));
	END IF;
	
	IF(p_current = p_max) THEN
		start_r := pi_found-pi_per_page+1;
	ELSIF(p_current = 1) THEN
		start_r := 1;		
	ELSIF(p_current != 1) THEN
		start_r := end_r-pi_per_page+1;
	END IF;
	
	IF(p_max = 0) THEN
		start_r := 0;
		end_r 	:= pi_per_page;			
	END IF;
	
else
	
	IF(pi_current = 0)THEN
		p_current := 1;	
		else
		p_current := pi_current;
	END IF; 
	IF(p_current != 1)THEN
		end_r := p_current*pi_per_page;
	ELSE
		end_r := pi_per_page;
	END IF;
	
	IF(p_current != 1)THEN
		start_r := (p_current-1)*pi_per_page+1;
	ELSE
		start_r := 1;
	END IF;
end if;	
	if(pi_type = 'start')then
		return start_r;
	else
		return end_r;
	end if;
END;
Author socket80. As is and under GPL ;)
 

Rezec

По пиву? (socket80)
И еще чуть-чуть ...
Dynamic SQL without probs.
PHP:
PROCEDURE xxx2(
	table                       IN varchar2,
	mycurs 		OUT TYPES.cursortype
)
   IS

	sql_stmt    VARCHAR2(1000);
		
BEGIN
sql_stmt    := 'SELECT * FROM '||table;
OPEN mycurs for  sql_stmt;
END;-- Procedure
 

Rezec

По пиву? (socket80)
Вопрос: Можно ли вместо флейма предложить свой вариант?
Ответ: Можно, если он существует.
 

chira

Новичок
Замена лимита:
Вернет с 5 по 10 строки
Код:
SELECT id
FROM mytable
WHERE ROWNUM <= 10
MINUS
SELECT id
FROM mytable
WHERE ROWNUM < 5
 

Rezec

По пиву? (socket80)
Интересно, есть ли разница между вложенным SELECT и двойным SELECT по количеству?
 

Vladimir

Guest
Автор оригинала: trent
тут не будет работать сортировка :)
select id from (
SELECT id
FROM mytable
WHERE ROWNUM <= 10
MINUS
SELECT id
FROM mytable
WHERE ROWNUM < 5
)

Так будет работать, правда толку никакого :)
 

Vladimir

Guest
Подобный вариант я пользую давно:
select <список полей> from (select <список полей>, rownum num_row from
(select <список полей> from table <условие> order by <поле для сортировки>)) where num_row >= $<строка начала> and num_row < $<строка окончания>
Но к сожалению он работает только в версиях 8i и старше.
В младших версиях запрещена сортировка во вложенных запросах.
Переменные передаются из скрипта, т.к. запрос кэшируется -
----------------
select <список полей> from table <условие> order by <поле для сортировки> - этот
----------------
то постраничный вывод весьма щустро работает.
 

romutis

Guest
Автор оригинала: socket80
Интересно, есть ли разница между вложенным SELECT и двойным SELECT по количеству?
Естественно. Двойной селект (такой как приведен в примере от chira) прочитает в общей сложности 10 записей, в то в время как твой прочитает все таблицу полностью. Разница налицо - особенно на больших таблицах.

Правда в примере от chira невозможно отсортировать данные, ну да это мелочи в борьбе за performance. :)
 

romutis

Guest
Автор оригинала: socket80
Вопрос: Можно ли вместо флейма предложить свой вариант?
Ответ: Можно, если он существует.
Придерживаясь темы топика, которая всё же звучала как "BULK COLLECTIONS - чего это такое ?", а не "Как бы мне ограничить данные SELECTa" привожу вариант:

Код:
TYPE TYPE_MTABLE IS TABLE OF <MY_TABLE>%ROWTYPE;

Declare
Cursor  Cur1 is SELECT * from <MY_TABLE> Where <My_Where_Req> Order by <My_Sort_Req>;
MTABLE TYPE_MTABLE := TYPE_MTABLE();
Num number;
Low_Limit Number := 6;

BEGIN
Open Cur1;
FETCH Cur1 BULK COLLECT INTO MTABLE LIMIT 10;
Close Cur1;
DBMS_OUTPUT.PUT_LINE(' I've read records from: '||Low_Limit||' to: '||MTABLE.COUNT);
FOR Num IN Low_Limit..MTABLE.COUNT LOOP
  DBMS_OUTPUT.PUT_LINE(' Record number: '||Num||'. Field Value: '||MTABLE(Num).<Field>);
END LOOP;
END;
Правда возникает вопрос - а где тут PHP? А я не знаю - кто такой PHP. :D
 
Сверху