Переключение на Главную Страницу Страницы: 1 [2]  ОтправитьПечать
Очень популярная тема (более 25 ответов) Как запросом получить наименование всех уровней? (число прочтений - 8582 )
mrgreen
Junior Member
**
Отсутствует


1C++ rocks!

Сообщений: 32
Зарегистрирован: 01. Августа 2009
Re: Как запросом получить наименование всех уровней?
Ответ #15 - 20. Августа 2009 :: 12:09
Печать  
Код
Выбрать все
Миллион элементов в 7ке? Нехилый справочник. 



ну там порядка 3х... весит полтора гига его таблица

это справочник изделий с группами год-месяц-день а служит для связки каждого изделия с штрихкодом и репликацией этих справочников между несколькими базами - плюс ссылка на сам вид товара - это другой справочник - там тыс. 40 пока и 4 уровня

посему и нужно чет универсальное т.е. не зависящее от количества групп в иерархии и работающее оооочень шустро

а то если без отбора по группам или дням (так же группам) получаем прирост раз в 20 а с проверкой вхождений тупизм в те же раз 20 Печаль

Код
Выбрать все
Профайлер - EM в меню Tools(Profiler) или в меню пуск в группе Microsoft SQL Server. Настраиваете отборы, запускаете трасу и смотрите какие запросы кидает 1С серверу. 



"охохох... что ж я маленький не сдох..." (с)

ладно... поанализируем дело нужное
  
Наверх
 
IP записан
 
alexdd
Senior Member
****
Отсутствует


I Love YaBB 2!

Сообщений: 347
Зарегистрирован: 25. Июня 2007
Re: Как запросом получить наименование всех уровней?
Ответ #16 - 20. Августа 2009 :: 12:17
Печать  
> ладно... поанализируем дело нужное
гениального 1С-запроса, думаю, там все равно не увидите, в справочнике дерево id,parentid. Если надо быстро, придется как-то модифицировать структуру справочника, чтобы не приходилось отбирать по уровню. Хранить уровень в поле или еще как
  
Наверх
 
IP записан
 
alexdd
Senior Member
****
Отсутствует


I Love YaBB 2!

Сообщений: 347
Зарегистрирован: 25. Июня 2007
Re: Как запросом получить наименование всех уровней?
Ответ #17 - 20. Августа 2009 :: 12:22
Печать  
и кстати 7ка то делает это быстро для одного элемента, типа спр.Уровень(). Ну так и функция для одного проверит моментально, а вот для пары миллионов - ой..
  
Наверх
 
IP записан
 
mrgreen
Junior Member
**
Отсутствует


1C++ rocks!

Сообщений: 32
Зарегистрирован: 01. Августа 2009
Re: Как запросом получить наименование всех уровней?
Ответ #18 - 20. Августа 2009 :: 12:38
Печать  
да там реальное отставание начинается на на первых сотнях Улыбка на самых больших группах я и не проверял... хватило и этой динамики

кстати попутно никто не в курсе как отключить это окошко о превышении длинны запроса (когда вставляю строку с ИД ами большого количества элементов) ?
  
Наверх
 
IP записан
 
Z1
God Member
*****
Отсутствует


I Love YaBB 2!

Сообщений: 2906
Местоположение: Москва
Зарегистрирован: 26. Мая 2006
Пол: Мужской
Re: Как запросом получить наименование всех уровней?
Ответ #19 - 20. Августа 2009 :: 12:47
Печать  
mrgreen писал(а) 20. Августа 2009 :: 11:57:
Код
Выбрать все
Тут пару дней назад постили функцию для проверки вхождения в группу  



это ту что я постил ? Улыбка она безбожно тупит если элементов за лимон (это же по каждому надо выбрать все группы вверх и вернуть ответ)

Код
Выбрать все
профайлер  



эээ... простите за тупизм а подробнее  ?


пысы... не ну проблема то решаема при помощи передачи списка элементов полученных простым 1це запросом по справочнику и выгрузкой его ИД-ов в строку подстановки при формировании текста запроса но это ведь некрасиво и насколько я помню IN таки ограничен по быстродействию

in необязателен.
делай join. Если надо много раз с одой временной таблицей то ее надо проиндексировать ( не знаю делается это или нет при уложитьсписок)
  
Наверх
 
IP записан
 
Z1
God Member
*****
Отсутствует


I Love YaBB 2!

Сообщений: 2906
Местоположение: Москва
Зарегистрирован: 26. Мая 2006
Пол: Мужской
Re: Как запросом получить наименование всех уровней?
Ответ #20 - 25. Августа 2009 :: 08:15
Печать  
mrgreen писал(а) 20. Августа 2009 :: 11:32:
задам вопрос тут Улыбка

необходимо проверить вхождение элемента в группу (это может быть и группа более верхнего уровня чем непосредственный родитель) как это сделать быстро, как отрабатывает метод "в ОбъектГруппа" в самой 1це ?

дело в том что пробовал через соединение с таблицей аналогом сдешней (и отбором по необходмой группе в любом поле из групп) - отрабатывает медленнее чем метод 1це

пробовал хранимой функцией - ещё раз в пять дольше получается

как 1це это делает так быстро ?!!!

Опиши подробней свою задачу здесь или в новой ветке.
Хватает ли тебе 10 уровней вложенности справочника
или как-то хитро выкручиваешься ?
  
Наверх
 
IP записан
 
mrgreen
Junior Member
**
Отсутствует


1C++ rocks!

Сообщений: 32
Зарегистрирован: 01. Августа 2009
Re: Как запросом получить наименование всех уровней?
Ответ #21 - 26. Августа 2009 :: 12:22
Печать  
Сама задача стандартна и состоит из одной задачи и одной подзадачи

Задача - использовать фильтр по группе элементов. Т.е. реализовать аналог "Условие (Номенклатура в ВыбГруппа)" с условием того что ВыбГруппа может и не являтся прямым родителем самого элемента... вобщем стандартное условие 1це

и ещё одна подзадача - вывод в результирующую таблицу полного наименования (вкл. всех родителей)... аналог ПолнНаименование() в 1це (из-за конкретных тормозов оригинальной функции)

собственно вторая реализуется функцией

Код
Выбрать все
CREATE FUNCTION Full_Name_Nom
(
	@NomID char(9)
)
RETURNS char(255)
AS
BEGIN
	DECLARE  @str char(255),@DESCR char(50),@strv char(255)
	SET @str = ''
	SET @DESCR = ''

	WHILE @NomID <> '     0   '
		BEGIN
			SELECT @DESCR = DESCR FROM  SC282 WHERE ID = @NomID
			SELECT @NomID = PARENTID FROM  SC282 WHERE ID = @NomID
			SET @str = '/'+RTRIM(LTRIM(@DESCR)) + LTRIM(RTRIM(@str))
		END
		SET @str = RIGHT(@str,254)+SPACE(1)
	RETURN @str
END 



а вот с самой задачей туго.. реализовывал различными методами

1

Код
Выбрать все
INNER JOIN (
						SELECT Gr3.ID As _Группа3, Gr3.DESCR As _Группа3Т,
							Gr2.ID As _Группа2, Gr2.DESCR As _Группа2Т,
							Gr1.ID As _Группа1, Gr1.DESCR As _Группа1Т,
							SprNom.ID As IDNOM,
							'('+SprNom.CODE+')' As _КодНом
					FROM SC282 As SprNom
					LEFT OUTER JOIN SC282 as Gr1 ON SprNom.PARENTID = Gr1.ID
					LEFT OUTER JOIN SC282 as Gr2 ON Gr1.PARENTID = Gr2.ID
					LEFT OUTER JOIN SC282 as Gr3 ON Gr2.PARENTID = Gr3.ID
					WHERE
					SprNom.ISFOLDER = 2 AND ((SprNom.PARENTID = '   4D8   ') or (Gr1.PARENTID = '   4D8   ') or (Gr2.PARENTID = '   4D8   '))
					GROUP BY Gr3.ID,Gr2.ID,Gr1.ID,Gr3.DESCR,Gr2.DESCR,Gr1.DESCR,SprNom.ID, '('+SprNom.CODE+')'
				) As Группы ON TMP._Номенклатура = Группы.IDNOM 



т.е. соединением таблицы всего выбранного справочника (отфилтрованного по необходимой группе) с итоговой выборкой

во-первых тянутся обе таблицы целиком изначально а во-вторых неудобно и геморойно генерить текст  в зависимости от кол-ва уровней справочника

2
на базе функции с получением полного наименования

Код
Выбрать все
CREATE FUNCTION INParent_Nom
(
	@NomID char(9),@ParentID char(9)
)
RETURNS char(255)
AS
BEGIN
	DECLARE  @F tinyint
	SET @F = 0
	WHILE @NomID <> '     0   '
		BEGIN
			SELECT @NomID = PARENTID FROM  SC282 WHERE ID = @NomID
					IF 	@NomID = @ParentID
						SET	@F = 1
		END
	RETURN @F
END 



в реальности оказалось ещё медленнее если вызываешь её на уровне получения таблицы итогов

Сейчас сделал (выкрутился) следующим образом - получаю список элементов входящих в группу (группы) обыкновенным 1це запросом а затем уже этот список передаю в качестве строки с ИД-ами в текст запроса
  
Наверх
 
IP записан
 
Z1
God Member
*****
Отсутствует


I Love YaBB 2!

Сообщений: 2906
Местоположение: Москва
Зарегистрирован: 26. Мая 2006
Пол: Мужской
Re: Как запросом получить наименование всех уровней?
Ответ #22 - 26. Августа 2009 :: 14:16
Печать  
Цитата:
Задача - использовать фильтр по группе элементов. Т.е. реализовать аналог "Условие (Номенклатура в ВыбГруппа)" с условием того что ВыбГруппа может и не являтся прямым родителем самого элемента... вобщем стандартное условие 1це

почему нельзя использовать УложитьСписокОбъектов
это будет всегда гораздо быстрее чем Стандарный запрос 1с
для формирования этого списка?
  
Наверх
 
IP записан
 
Z1
God Member
*****
Отсутствует


I Love YaBB 2!

Сообщений: 2906
Местоположение: Москва
Зарегистрирован: 26. Мая 2006
Пол: Мужской
Re: Как запросом получить наименование всех уровней?
Ответ #23 - 26. Августа 2009 :: 14:29
Печать  
Цитата:
в реальности оказалось ещё медленнее если вызываешь её на уровне получения таблицы итогов

Конечно только не функция медленная ( я считаю что вместо функции лучше использовать хранимую процедуру )
а просто эту функцию вызываем очень много раз.
sql любит один сложный запрос на  1 000 000 строк
чем наоборот 1 000 000 запросов каждый возвращающий
по одной строке.
Так что выхода два написать на t-sql процедуру генерящюю
полные имена сразу для множества элементов,
либо что я считаю более правильным для твоей задачи
хранить в элементе полное наименование тогда его не нужно будет вычислять вообще
(изменения подчинения происходят гораздо реже чем запросы
формируемые с учетом дерева ).
Конечно при изменении Родителя придеться у всей подчиненной ветке менять наименование.


PS для функции NParent_Nom можно поставить (nolock) тогда функция
не будет ждать если sql по каким то причинам заблокирует весь
справочник, или частично из-за индекса ( и.т.д)
  
Наверх
 
IP записан
 
mrgreen
Junior Member
**
Отсутствует


1C++ rocks!

Сообщений: 32
Зарегистрирован: 01. Августа 2009
Re: Как запросом получить наименование всех уровней?
Ответ #24 - 27. Августа 2009 :: 08:59
Печать  
Цитата:
почему нельзя использовать УложитьСписокОбъектов
это будет всегда гораздо быстрее чем Стандарный запрос 1с
для формирования этого списка?


да можно но хотелось же чистого SQL без привязки текста именно к парсеру 1с++

Код
Выбрать все
sql любит один сложный запрос на  1 000 000 строк
чем наоборот 1 000 000 запросов каждый возвращающий
по одной строке. 



это да но как-то же 1це это таки делает (ну не поверю что выгружает всю таблицу и джойнит её с итогами или санчала делает выборку ПринадлежитГруппе а потом элементы вставляет в запрос) и делает очень шустро... скажем в её хранимках похожего не нашёл


  
Наверх
 
IP записан
 
Z1
God Member
*****
Отсутствует


I Love YaBB 2!

Сообщений: 2906
Местоположение: Москва
Зарегистрирован: 26. Мая 2006
Пол: Мужской
Re: Как запросом получить наименование всех уровней?
Ответ #25 - 27. Августа 2009 :: 09:31
Печать  

Цитата:
да можно но хотелось же чистого SQL без привязки текста именно к парсеру 1с++

ну если так хочеться то посмотри как в 1с++ сделан метод УложитьСписокОбъектов
и сделай также сам по аналогии.
  
Наверх
 
IP записан
 
Z1
God Member
*****
Отсутствует


I Love YaBB 2!

Сообщений: 2906
Местоположение: Москва
Зарегистрирован: 26. Мая 2006
Пол: Мужской
Re: Как запросом получить наименование всех уровней?
Ответ #26 - 27. Августа 2009 :: 09:32
Печать  
Цитата:
это да но как-то же 1це это таки делает (ну не поверю что выгружает всю таблицу и джойнит её с итогами или санчала делает выборку ПринадлежитГруппе а потом элементы вставляет в запрос)

Так есть же профайлер sql.
Если интересно то смотри как работает Спр.ПолноеНаименование();
  
Наверх
 
IP записан
 
Salimbek
God Member
*****
Отсутствует



Сообщений: 862
Зарегистрирован: 06. Июня 2006
Пол: Мужской
Re: Как запросом получить наименование всех уровней?
Ответ #27 - 08. Сентября 2009 :: 13:54
Печать  
mrgreen писал(а) 26. Августа 2009 :: 12:22:
Сама задача стандартна и состоит из одной задачи и одной подзадачи

Задача - использовать фильтр по группе элементов. Т.е. реализовать аналог "Условие (Номенклатура в ВыбГруппа)" с условием того что ВыбГруппа может и не являтся прямым родителем самого элемента... вобщем стандартное условие 1це

...
а вот с самой задачей туго.. реализовывал различными методами
...

Сейчас сделал (выкрутился) следующим образом - получаю список элементов входящих в группу (группы) обыкновенным 1це запросом а затем уже этот список передаю в качестве строки с ИД-ами в текст запроса

А я использую - "УложитьСписокОбъектов(ВыбГруппа,"#tmp","Номенклатура");"
И далее
"WHERE Номенклатура.ID IN (SELECT Val FROM #tmp)" - вроде быстро работает
  
Наверх
ICQ  
IP записан
 
shmalevoz
Junior Member
**
Отсутствует


1C++ rocks!

Сообщений: 55
Зарегистрирован: 23. Апреля 2009
Re: Как запросом получить наименование всех уровней?
Ответ #28 - 26. Сентября 2009 :: 03:43
Печать  
Попробуй вот такой код, у меня отрабатывает вроде в приемлемое время.
Код
Выбрать все
create function refGetGroupsTreeIDs
	(
		@ParentGroupID char (9)	-- исходный родитель
	)
	returns
		@retval table		-- возвращаем таблицу
		(
			[ID] char (9)	-- в которой содержатся идентификаторы нижестоящих групп
		)
as
begin

	insert @retval select @ParentGroupID	-- добавим текущую группу
	declare @group_id char(9)
	declare crSub cursor for		-- выборка нижестоящих групп
		select [ID]
		from sc84
		where
			[PARENTID] = @ParentGroupID
			and
			[ISFOLDER] = 1

	open crSub
	fetch next from crSub into @group_id
	while @@FETCH_STATUS = 0
	begin
		-- для каждой нижестоящей группы определимся с подгруппами
		insert @retval select * from refGetGroupsTreeIDs(@group_id)
		fetch next from crSub into @group_id
	end

	close crSub
	deallocate crSub

	return
end
 



Для проверка принадлежности элемента, например, '    AA   ' группе '    BB   '
Код
Выбрать все
select * from sc84
where
 [id]='    AA   '
 and
 [parentid] in refGetGroupsTreeIDs('    BB   ')
 

  
Наверх
 
IP записан
 
shmalevoz
Junior Member
**
Отсутствует


1C++ rocks!

Сообщений: 55
Зарегистрирован: 23. Апреля 2009
Re: Как запросом получить наименование всех уровней?
Ответ #29 - 26. Сентября 2009 :: 04:23
Печать  
И метод для получения полного наименования
Код
Выбрать все
create function refGetFullDescr
	(
		@ref char(9)
	)
	returns varchar(1200)	-- должно хватить и 1000, но уж для подстраховки =))
as
begin

	declare @retval varchar(1200)
	declare @parent char(9)
	declare @null_id char(9)
	declare @descr varchar(100)
	set @null_id = '     0   '
	set @retval = ''

	-- выберем интересующие нас поля
	declare cr cursor for
		select [parentid], [descr]
		from sc84
		where
			[id] = @ref

	open cr
	fetch next from cr into @parent, @descr
	while @@FETCH_STATUS = 0
	begin
		if @parent <> @null_id
		begin
			set @retval = dbo.refGetFullDescr(@parent) + '/'
		end
		set @retval = @retval + ltrim(rtrim(@descr))
		fetch next from cr into @parent, @descr
	end

	close cr
	deallocate cr

	return @retval
end
 

  
Наверх
 
IP записан
 
Переключение на Главную Страницу Страницы: 1 [2] 
ОтправитьПечать