Процедуры выборки в InterBase


1. CREATE PROCEDURE GETCHILDREN (STARTING_ITEM_ID SMALLINT, THISLEVEL SMALLINT) 2. RETURNS(ITEM_ID SMALLINT, DESCRIPTION CHAR(30), ITEMLEVEL SMALLINT) AS 3. BEGIN 4. FOR 5. SELECT T1.ITEM_IDM T1.DESCRIPTION 6. FROM ITEMS T1 7. WHERE T1.PARENT_ID = :STARTING_ITEM_ID 8. INTO :ITEM_ID, :DESCRIPTION 9. DO BEGIN 10. ITEMLEVEL = THISLEVEL + 1; 11. SUSPEND; 12. FOR 13. SELECT T1.ITEM_ID, T1.DESCRIPTION, T1.ITEMLEVEL 14. FROM GETCHILDREN(:ITEM_ID, :ITEMLEVEL) T1 15. INTO :ITEM_ID, :DESCRIPTION, :ITEMLEVEL 16. DO BEGIN 17. SUSPEND; 18. END 19. END 20. END;

Подобные итерации идеально подходят для просмотра иерархических данных в обоих направлениях, потому что сохраненные процедуры рекурсивны. Такую процедуру можно вызывать из нее самой, чтобы определить детей текущего объекта, затем получить их детей и т. д. Вместо того чтобы сразу получить все записи одного поколения и переходить к следующему, при этой стратегии мы сначала определяем первого потомка объекта, затем — его первого потомка (т. е. первого внука исходного объекта) и т. д. до нахождения последнего потомка.

На языке InterBase SUSPEND означает, что возвращаемая по RETURNS информация должна заноситься в результирующий набор в виде очередной записи. Первый оператор SUSPEND (строка 11) возвращает значения из первой записи запроса, определяющего непосредственных потомков STARTING_ITEM_ID (строки 5_8). Следующий SUSPEND (строка 17) возвращает результат рекурсив ного вызова процедуры выбора GETCHILDREN. До тех пор пока этот второй вызов находит записи (то есть до тех пор, пока у объекта находятся потомки), второй SUSPEND возвращает их исходной вызывающей процедуре. Когда объекты кончаются, вызывающий код продолжает свою работу и с помощью первого SUSPEND возвращает вторую запись исходного запроса. Если не сбросить переменную ITEMLEVEL во внешнем цикле (строка 10), в ней будет храниться значение из последней итерации внутреннего цикла (строка 15).

Для вызова процедур выборки InterBase следует пользоваться компонентом TQuery, а не TStoredProc. Синтаксис выглядит просто:

with Query1 do begin SQL.Clear; SQL.Add('SELECT * FROM GetChildren(' + IntToStr(CurrentItemID) + ',0)');
Open; end;

Полученный набор будет содержать всех потомков текущего объекта с указанием их уровня.



Содержание раздела