CREATE TABLE dbo.tmc
(
ITEM_ID CHAR(14) NOT NULL,
NAME CHAR(25) NOT NULL
ISGROUP NUMERIC(1,0) NULL,
LEVEL_ NUMERIC(1,0) NULL,
PARENT CHAR(14) NULL,
CONSTRAINT kod PRIMARY KEY (KOD)
)
Выбрать только записи, пренадлежащие к группе и ее подгруппам
Имеется таблица:
Код:
Тестовые данные:
Код:
INSERT INTO dbo.tmc(ITEM_ID,NAME,ISGROUP,LEVEL_,PARENT)
VALUES ('1','Группа,из нее надо выбрать',1,1,'')
INSERT INTO dbo.tmc(ITEM_ID,NAME,ISGROUP,LEVEL_,PARENT)
VALUES ('1499','Группа,дочерняя из нее тоже',1,2,'1')
INSERT INTO dbo.tmc(ITEM_ID,NAME,ISGROUP,LEVEL_,PARENT)
VALUES ('1479','Запись которую надо',0,3,'1')
INSERT INTO dbo.tmc(ITEM_ID,NAME,ISGROUP,LEVEL_,PARENT)
VALUES ('8','Группа дочерняя2 из нее тоже',1,3,'1499')
INSERT INTO dbo.tmc(ITEM_ID,NAME,ISGROUP,LEVEL_,PARENT)
VALUES ('10','Запись которую надо2',0,5,'8')
INSERT INTO dbo.tmc(ITEM_ID,NAME,ISGROUP,LEVEL_,PARENT)
VALUES ('20','Группа не надо выбирать',1,1,'')
INSERT INTO dbo.tmc(ITEM_ID,NAME,ISGROUP,LEVEL_,PARENT)
VALUES ('25','Запись не должна быть выбрана',0,2,'20')
VALUES ('1','Группа,из нее надо выбрать',1,1,'')
INSERT INTO dbo.tmc(ITEM_ID,NAME,ISGROUP,LEVEL_,PARENT)
VALUES ('1499','Группа,дочерняя из нее тоже',1,2,'1')
INSERT INTO dbo.tmc(ITEM_ID,NAME,ISGROUP,LEVEL_,PARENT)
VALUES ('1479','Запись которую надо',0,3,'1')
INSERT INTO dbo.tmc(ITEM_ID,NAME,ISGROUP,LEVEL_,PARENT)
VALUES ('8','Группа дочерняя2 из нее тоже',1,3,'1499')
INSERT INTO dbo.tmc(ITEM_ID,NAME,ISGROUP,LEVEL_,PARENT)
VALUES ('10','Запись которую надо2',0,5,'8')
INSERT INTO dbo.tmc(ITEM_ID,NAME,ISGROUP,LEVEL_,PARENT)
VALUES ('20','Группа не надо выбирать',1,1,'')
INSERT INTO dbo.tmc(ITEM_ID,NAME,ISGROUP,LEVEL_,PARENT)
VALUES ('25','Запись не должна быть выбрана',0,2,'20')
Задача стоит в следующем - выбрать только те записи, которые пренадлежат к указаной группе и ее подгруппам. Т.е. например у меня есть ХП которая возвращает тру либо фалс - если запись соответственно принадлежит либо не принадлежит требуемой группе. По идее нужен запрос вида
Код:
select t.item_id, t.name from tmc t where ... AND EXEC is_group(t.parent) = 1
но как это реализовать в указанной БД?
Код:
elect t.item_id, t.name FROM tmc t WHERE ... AND is_group(t.parent) = 1
должно отрабатывать
Хотя в sybase'e возможно придется создать proxy - табличку для хранимой процедуры.
Код:
SELECT
KOD,
KUZOV,
PARENT FROM dbo.f_spr_tmc t
WHERE KUZOV !='' AND kuzov like '444' AND dbo.sp_in_group(PARENT,'1') = 1
KOD,
KUZOV,
PARENT FROM dbo.f_spr_tmc t
WHERE KUZOV !='' AND kuzov like '444' AND dbo.sp_in_group(PARENT,'1') = 1
дает вот такую ошибку
Цитата:
Error (2809) The request for function 'dbo.sp_in_group' failed because 'dbo.sp_in_group' is a procedure object.
т.е. мне получается надо создавать пользовательскую функцию? как это делается в сайбесе? Но вообще то если это возможно - как в запросе получить возвращаемое значение из процедуры?
http://infocenter.sybase.com/help/index.jsp?topic=/com.sybase.infocenter.dc36272.1502/html/commands/CHDEDGJI.htm
http://www.sypron.nl/udf.html#sqludf
В 12-м функции только как обертки для java.
http://infocenter.sybase.com/help/topic/com.sybase.dc36271_36272_36273_36274_1250/html/refman/BABBABJC.htm
Поетому скорее всего придется делать с прокси табличкой.
[COLOR="silver"]sap такой sap[/COLOR]
Текущее решение - открыть курсор (либо временную таблицу) в процедуре - пройтись по ней и удалить все записи для которых процедура возращает 0 - и оставшееся вернуть клиенту. но мне кажется что это немного не оптимально.
Поэтому мое решение - использовать две процедуры и временную таблицу с курсором.
У меня это выглядит так - первая процедура всего навсего определяет входит ли запись в требуемую группу:
Код:
CREATE PROCEDURE dbo.sp_in_group
@tree_id CHAR(14), /*Родительский идентификатор текущей записи*/
@group_id CHAR(14) /*Идентификатор группы на принадлежность к которой проверяем*/
AS
DECLARE @current_id CHAR(14)
BEGIN
WHILE (@tree_id IS NOT NULL AND @tree_id <>'')
BEGIN
/*Выбрали запись - проверили ее - если родитель пустой - завершаем - это корень дерева*/
select @current_id = t.kod, @tree_id = rtrim(t.parent)
from f_spr_tmc t
WHERE t.kod = @tree_id
end
IF @group_id = @current_id /*если идентификаторы совпадают - то хорошо*/
RETURN 1
ELSE
RETURN 0
END
@tree_id CHAR(14), /*Родительский идентификатор текущей записи*/
@group_id CHAR(14) /*Идентификатор группы на принадлежность к которой проверяем*/
AS
DECLARE @current_id CHAR(14)
BEGIN
WHILE (@tree_id IS NOT NULL AND @tree_id <>'')
BEGIN
/*Выбрали запись - проверили ее - если родитель пустой - завершаем - это корень дерева*/
select @current_id = t.kod, @tree_id = rtrim(t.parent)
from f_spr_tmc t
WHERE t.kod = @tree_id
end
IF @group_id = @current_id /*если идентификаторы совпадают - то хорошо*/
RETURN 1
ELSE
RETURN 0
END
В процедуру естественно надо передавать идентификатор корневой папки - но не стоставляет труда модифицировать процедуру так, что бы проверяла на любом уровне вложенности. Думаю это понятно.
И процедура которая обрабатывает данные:
Код:
CREATE PROCEDURE dbo.sp_select_auto
@kusov VARCHAR(25)
AS
BEGIN
DECLARE @current_id CHAR(14)
DECLARE @current_parent CHAR(14)
DECLARE @current_body CHAR(25)
DECLARE @result INT
/*создали таблицу, назначили ей первичный ключ - так как курсор у нас модифицирующий*/
CREATE TABLE #tmp_list_cars
(item_id CHAR(14),body_numb CHAR(25),parent CHAR(14), CONSTRAINT kod PRIMARY KEY (item_id))
/*заполнили ее*/
INSERT #tmp_list_cars
SELECT kod,kuzov,parent FROM f_spr_tmc WHERE KUZOV !='' AND KUZOV LIKE ('%'+rtrim(@kusov)+'%')
/*курсор создали*/
DECLARE list_cars CURSOR FOR SELECT item_id,body_numb,parent FROM #tmp_list_cars
FOR UPDATE
/*Открыли*/
OPEN list_cars
FETCH list_cars INTO @current_id,@current_body,@current_parent
WHILE @@sqlstatus = 0
BEGIN
EXEC @result = sp_in_group @current_parent,'1'
IF @result = 0
BEGIN
DELETE FROM #tmp_list_cars WHERE current of list_cars
END
FETCH list_cars INTO @current_id,@current_body,@current_parent
END
CLOSE list_cars
deallocate CURSOR list_cars /*убираем за собой*/
SELECT item_id AS auto_id, body_numb AS kuzov FROM #tmp_list_cars
DROP TABLE #tmp_list_cars
END
@kusov VARCHAR(25)
AS
BEGIN
DECLARE @current_id CHAR(14)
DECLARE @current_parent CHAR(14)
DECLARE @current_body CHAR(25)
DECLARE @result INT
/*создали таблицу, назначили ей первичный ключ - так как курсор у нас модифицирующий*/
CREATE TABLE #tmp_list_cars
(item_id CHAR(14),body_numb CHAR(25),parent CHAR(14), CONSTRAINT kod PRIMARY KEY (item_id))
/*заполнили ее*/
INSERT #tmp_list_cars
SELECT kod,kuzov,parent FROM f_spr_tmc WHERE KUZOV !='' AND KUZOV LIKE ('%'+rtrim(@kusov)+'%')
/*курсор создали*/
DECLARE list_cars CURSOR FOR SELECT item_id,body_numb,parent FROM #tmp_list_cars
FOR UPDATE
/*Открыли*/
OPEN list_cars
FETCH list_cars INTO @current_id,@current_body,@current_parent
WHILE @@sqlstatus = 0
BEGIN
EXEC @result = sp_in_group @current_parent,'1'
IF @result = 0
BEGIN
DELETE FROM #tmp_list_cars WHERE current of list_cars
END
FETCH list_cars INTO @current_id,@current_body,@current_parent
END
CLOSE list_cars
deallocate CURSOR list_cars /*убираем за собой*/
SELECT item_id AS auto_id, body_numb AS kuzov FROM #tmp_list_cars
DROP TABLE #tmp_list_cars
END
вот такое решение в данном случае. А вообще конечно в норме стоит использовать промежуточную таблицу - это весьма упрощает жизнь и ускоряет выборки.
Ну и да - у кого есть решение по-лучше (кроме как написать явовскую обертку, либо сменить версию сервера) то опишите.
Христос народився! Славимо його! С праздником.