Переключение на Главную Страницу Страницы: [1] 2  ОтправитьПечать
Горячая тема (более 10 ответов) Использование цикла по перебору справочника в запросе (число прочтений - 6192 )
Inner Join (c)
Junior Member
**
Отсутствует


I Love BaBB 2!

Сообщений: 23
Зарегистрирован: 15. Октября 2008
Пол: Мужской
Использование цикла по перебору справочника в запросе
16. Апреля 2009 :: 11:28
Печать  
Доброе время суток!
Есть справочник Товары и подчиненный ему справочник Единицы. В единицах беспорядочно установлены коды элементов. Нужно установить для базовой единицы (определяется по перечислению в справочнике Товары) код 1. Для единиц с типами уп, кор, палето далее по последовательности (имеется ввиду если есть несколько одинаковых типов).
В общем придумал такую схему: для определенного товара выгрузить все его единицы в таблицу добавив колонку параметр (базовая-1, уп-2, кор-3, палето-4). Отсортировать "Колонка-параметр,ИДЭлемента". Затем по номерам строк данной таблицы задать коды в справочнике Единицы.
Можно канешн создать параметризированный запрос для выгрузки единиц в 1с-кую ТЗ, сортировать, добавить столбец с номерами строк и «заапдейтить» единицы по этой ТЗ. Но хотелось бы сделать подобное через SQL. Первый раз задался такой идеей. Раньше хватало обычной выборки с различными соединениями. Никода не использовал запросы с циклами и условиями, но очень хочетца разобраться.  Улыбка Да и скорость удивительная по сравнению с 1С.

В общем получилось что-то вроде:

if Exists (select * from tempdb..sysobjects where id = object_id('tempdb..#temp_ed') and sysstat & 0xf = 3 ) drop table #temp_ed
Create Table #temp_ed ( [row_id] int IDENTITY(1, 1) not null, [id] char(9), [p] int, PRIMARY KEY CLUSTERED (row_id) )
DECLARE @code as int
SET @code = (select max(code) from $Справочник.Товары (nolock))

WHILE @code > 0
BEGIN
delete from #temp_ed

if not Exists (select * from $Справочник.Товары (nolock) where code = @code) begin set @code = @code - 1 continue end

insert into #temp_ed (id, p)
select
e.id id,
case
when $e.спрЕдиница = $t.спрБазоваяЕдиница then 1
when $e.спрЕдиница = :Упаковка then 2
when $e.спрЕдиница = :Коробка then 3
when $e.спрЕдиница = :Палето then 4
else 5
end p
from $Справочник.Товары t (nolock)
inner join $Справочник.Единицы e (nolock) on t.id = e.parentext and t.code = @code
order by p, id

if @@ROWCOUNT > 0 begin
update e
set e.code = t.row_id
from $Справочник.Единицы e (nolock)
inner join #temp_ed t on t.id = e.id
end

set @code = @code - 1
END

GO
select
t.row_id,
t.id,
t.p,
e.code,
tov.code
from #temp_ed t
inner join $Справочник.Единицы e (nolock) on e.id = t.id
inner join $Справочник.Товары tov (nolock) on tov.id = e.parentext

if Exists (select * from tempdb..sysobjects where id = object_id('tempdb..#temp_ed') and sysstat & 0xf = 3 ) drop table #temp_ed

Получаю максимальный код в справочнике Товары. Далее обратный цикл по кодам товаров для получения единиц с параметром…
Тока не работает она, чтоб ее... С конкретным указанием кода все отлично, но с циклом что-то не так. Если убрать delete from #temp_ed, то в таблице две строки на выходе. С единицами двух товаров с последними по величине кодов.

Еще смущает то, что если в «set @code = @code - 1» поставить «+ 100» то ничего странного не происходит. Время обработки прежнее. Результат тоже  Озадачен
Чет запутался .......
  
Наверх
 
IP записан
 
leshik
1c++ donor
Отсутствует



Сообщений: 820
Местоположение: Пятигорск
Зарегистрирован: 22. Апреля 2007
Пол: Мужской
Re: Использование цикла по перебору справочника в запросе
Ответ #1 - 16. Апреля 2009 :: 12:19
Печать  
Имхается мне, что можно получить все одним запросом, а потом стандартно установить Подмигивание)) ну или не стандартно установить
  
Наверх
IP записан
 
leshik
1c++ donor
Отсутствует



Сообщений: 820
Местоположение: Пятигорск
Зарегистрирован: 22. Апреля 2007
Пол: Мужской
Re: Использование цикла по перебору справочника в запросе
Ответ #2 - 16. Апреля 2009 :: 12:36
Печать  
Код
Выбрать все
Select
  ИтЗапрос.Товар [Товар $Справочник.Товары]
, ИтЗапрос.Единица [Единица $Справочник.Единицы]
, ИтЗапрос.ПризнакСортировки as ПризнакСортировки
From
(
Select
 СпрТов.ID as Товар
,СпрЕд.ID as Единица
,CASE
  When $СпрТов.БазоваяЕдиница = СпрЕд.ID Then 1
  When $СпрЕд.спрЕдиница = :Упаковка Then 2
  ....
  END
  as ПризнакСортировки
From $Справочник.Товары as СпрТов (NOLOCK)
LEFT JOIN $Справочник.Единицы as СпрЕд (NOLOCK) on
(СпрТов.id = СпрЕд.parentext)
Where СпрТов.ISFOLDER = 2
) as ИтЗапрос
Order By ИтЗапрос.Товар, ИтЗапрос.ПризнакСортировки 


ну а потом пробежать по индексированной таблице и перекодировать
  
Наверх
IP записан
 
Inner Join (c)
Junior Member
**
Отсутствует


I Love BaBB 2!

Сообщений: 23
Зарегистрирован: 15. Октября 2008
Пол: Мужской
Re: Использование цикла по перебору справочника в запросе
Ответ #3 - 16. Апреля 2009 :: 12:47
Печать  
(1-2) Согласен Улыбка Правильных вариантов решения данной проблемы не мало. Но неизученный "WHILE" давно уже гложет страшно  Смех Там ведь до решения чуть осталось... Ведь с прямым указанием кода товара и комментированным циклом все чудесно.
Научусь цикл использовать, как в нужный момент жисть спасет Улыбка
  
Наверх
 
IP записан
 
Z1
God Member
*****
Отсутствует


I Love YaBB 2!

Сообщений: 2906
Местоположение: Москва
Зарегистрирован: 26. Мая 2006
Пол: Мужской
Re: Использование цикла по перебору справочника в запросе
Ответ #4 - 16. Апреля 2009 :: 12:50
Печать  
Inner Join (c) писал(а) 16. Апреля 2009 :: 12:47:
(1-2) Согласен Улыбка Правильных вариантов решения данной проблемы не мало. Но неизученный "WHILE" давно уже гложет страшно  Смех Там ведь до решения чуть осталось... Ведь с прямым указанием кода товара и комментированным циклом все чудесно.
Научусь цикл использовать, как в нужный момент жисть спасет Улыбка

наоборот забывай про while.   sql   декларативный язык и
в "чистом" ansi sql нет и не может быть while.
ИХМО изучай код который для тебя leshik написал.
  
Наверх
 
IP записан
 
Inner Join (c)
Junior Member
**
Отсутствует


I Love BaBB 2!

Сообщений: 23
Зарегистрирован: 15. Октября 2008
Пол: Мужской
Re: Использование цикла по перебору справочника в запросе
Ответ #5 - 16. Апреля 2009 :: 12:51
Печать  
просто изначально отбросил все доступные варианты решения и задался идеей "потоки" поизучать Улыбка
  
Наверх
 
IP записан
 
Inner Join (c)
Junior Member
**
Отсутствует


I Love BaBB 2!

Сообщений: 23
Зарегистрирован: 15. Октября 2008
Пол: Мужской
Re: Использование цикла по перебору справочника в запросе
Ответ #6 - 16. Апреля 2009 :: 12:56
Печать  
Z1 писал(а) 16. Апреля 2009 :: 12:50:
Inner Join (c) писал(а) 16. Апреля 2009 :: 12:47:
(1-2) Согласен Улыбка Правильных вариантов решения данной проблемы не мало. Но неизученный "WHILE" давно уже гложет страшно  Смех Там ведь до решения чуть осталось... Ведь с прямым указанием кода товара и комментированным циклом все чудесно.
Научусь цикл использовать, как в нужный момент жисть спасет Улыбка

наоборот забывай про while.   sql   декларативный язык и
в "чистом" ansi sql нет и не может быть while.
ИХМО изучай код который для тебя leshik написал.


Жаль. Творческий процесс почти уничтожен.... Кстати решил "While" изучить после того как его здесь на форуме его увидел. Народ так лихо им оперировал, что сразу натолкнуло на мысль изучить его.
  
Наверх
 
IP записан
 
Inner Join (c)
Junior Member
**
Отсутствует


I Love BaBB 2!

Сообщений: 23
Зарегистрирован: 15. Октября 2008
Пол: Мужской
Re: Использование цикла по перебору справочника в запросе
Ответ #7 - 16. Апреля 2009 :: 13:34
Печать  
leshik писал(а) 16. Апреля 2009 :: 12:36:
Код
Выбрать все
Select
  ИтЗапрос.Товар [Товар $Справочник.Товары]
, ИтЗапрос.Единица [Единица $Справочник.Единицы]
, ИтЗапрос.ПризнакСортировки as ПризнакСортировки
From
(
Select
 СпрТов.ID as Товар
,СпрЕд.ID as Единица
,CASE
  When $СпрТов.БазоваяЕдиница = СпрЕд.ID Then 1
  When $СпрЕд.спрЕдиница = :Упаковка Then 2
  ....
  END
  as ПризнакСортировки
From $Справочник.Товары as СпрТов (NOLOCK)
LEFT JOIN $Справочник.Единицы as СпрЕд (NOLOCK) on
(СпрТов.id = СпрЕд.parentext)
Where СпрТов.ISFOLDER = 2
) as ИтЗапрос
Order By ИтЗапрос.Товар, ИтЗапрос.ПризнакСортировки 


ну а потом пробежать по индексированной таблице и перекодировать


Тока зачем тогда подзапрос использовать, если можно в основном тотже результат получить, и left join думаю можно заменить на inner, т.к. товар без единиц нас вообще не интересует. Но эт мелочи Улыбка
Не совсем понял как из общей таблицы с товарами единицами (повторяющимися), признаком сортировки (тоже повторяющимся) получить уникальные коды единиц в пределах каждого подчинения товару  Озадачен
  
Наверх
 
IP записан
 
leshik
1c++ donor
Отсутствует



Сообщений: 820
Местоположение: Пятигорск
Зарегистрирован: 22. Апреля 2007
Пол: Мужской
Re: Использование цикла по перебору справочника в запросе
Ответ #8 - 16. Апреля 2009 :: 13:54
Печать  
Цитата:
Тока зачем тогда подзапрос использовать

Для сортировки по полю ПризнакСортировки
А касательно задачи так и не понятно - что сделать то надо.
Выдели в отдельный пост только задачу - что есть и что надо сделать. А там подумаем.
  
Наверх
IP записан
 
Inner Join (c)
Junior Member
**
Отсутствует


I Love BaBB 2!

Сообщений: 23
Зарегистрирован: 15. Октября 2008
Пол: Мужской
Re: Использование цикла по перебору справочника в запросе
Ответ #9 - 17. Апреля 2009 :: 06:46
Печать  
Дожно быть например так:

Товар 1
    |   (подч. спр. Единицы)
    |-- 1 / шт. / Коэф 1
    |-- 2 / уп. / Коэф 10
    |-- 3 / уп. / Коэф 50
    |-- 4 / кор. / Коэф 1000
    |-- 5 / Палето / Коэф 10000

Сейчас коды беспорядочно установлены. В разных базах имеются расхождения в кодах при одинаковом составе единиц. И при обмене (связь по коду элем.) связь рушится. Нужно коды установить одинаковыми во всех базах причем по определенному правилу, описанному в посте (1).

Честно говоря не вижу решения данной проблемы без получения таблицы единиц поочередно для каждого товара, их упорядочивания, затем по номерам строк установки уникальных кодов элементов.
Либо через получение общей таблицы, содержащей товары, единицы, признак для упорядочивания, а также изначально пустую колонку с кодами. Затем 1с-ным способом проставить нужные номера в пустой колонке (перебором строк или при помощи подмножеств строк "AddIn.ValTable"), тем самым получив коды единиц конкретного товара.

Но используя один запрос, не выгружая данные в память из sql, затем обратно, все происходит мнгновенно.... 1-1,5 сек. При том что наименований товаров ок. 35 тыс. У каждого из них единиц от 1 до 10.
Как я уже говорил, запрос в посте (1) с конкретным указанием кода товара все работет....  Улыбка Цикл не правильно написан чтоли  Озадачен Тока не пойму где...
  
Наверх
 
IP записан
 
Inner Join (c)
Junior Member
**
Отсутствует


I Love BaBB 2!

Сообщений: 23
Зарегистрирован: 15. Октября 2008
Пол: Мужской
Re: Использование цикла по перебору справочника в запросе
Ответ #10 - 17. Апреля 2009 :: 07:07
Печать  
leshik писал(а) 16. Апреля 2009 :: 13:54:
Цитата:
Тока зачем тогда подзапрос использовать

Для сортировки по полю ПризнакСортировки
А касательно задачи так и не понятно - что сделать то надо.
Выдели в отдельный пост только задачу - что есть и что надо сделать. А там подумаем.


А сортировка по алиасу в одном запросе.  Подмигивание Не знаю как в оригинальном sql, но в 1с++ работает. Сортировка и группировка работает также и по case... типа в полях его прописываешь и в сортировке. Но это канешн страшновато выглядит Смех

leshik, а ты как-то про индексированную таблицу упоминал. Я индексы обычно для ускорения обработки больших объемов применял и не знаю всех их возможностей (если они канешн есть Улыбка ). Нельзя ли их в моем случае использовать? Типа индекс по двум полям (товар, единица) потом использовать при обработке всей таблицы.
  
Наверх
 
IP записан
 
alexdd
Senior Member
****
Отсутствует


I Love YaBB 2!

Сообщений: 347
Зарегистрирован: 25. Июня 2007
Re: Использование цикла по перебору справочника в запросе
Ответ #11 - 17. Апреля 2009 :: 17:29
Печать  
В справочнике code - это char, @code у вас int, там непойми что получится..
тогда уж
SET @code = (select max(cast(code as int)) from $Справочник.Товары (nolock))
и
if not Exists (select * from $Справочник.Товары (nolock) where rtrim(ltrim(code)) = cast(@code as varchar) begin ...
и т.д.
но
leshik писал(а) 16. Апреля 2009 :: 12:19:
Имхается мне, что можно получить все одним запросом, а потом стандартно установить Подмигивание)) ну или не стандартно установить

+1 Класс
  
Наверх
 
IP записан
 
Inner Join (c)
Junior Member
**
Отсутствует


I Love BaBB 2!

Сообщений: 23
Зарегистрирован: 15. Октября 2008
Пол: Мужской
Re: Использование цикла по перебору справочника в запросе
Ответ #12 - 21. Апреля 2009 :: 07:05
Печать  
черт. вот ложанулся  Улыбка тримнуть забыл...
обычно всегда без cast'a обходился. всмсле "where rtrim(ltrim(code)) = rtrim(ltrim(@code))".
А "(select max(code) from $Справочник.Товары (nolock))" нормально срабатывал и циферку возвращал  Подмигивание видимо тоже неявное преобразование

ЗЫ запрос перепишу без цикла. как оформлю выложу
  
Наверх
 
IP записан
 
Z1
God Member
*****
Отсутствует


I Love YaBB 2!

Сообщений: 2906
Местоположение: Москва
Зарегистрирован: 26. Мая 2006
Пол: Мужской
Re: Использование цикла по перебору справочника в запросе
Ответ #13 - 21. Апреля 2009 :: 07:39
Печать  
Так если у тебя коды только целые может тебе в подчиненном справочнике завести Новый реквизит
ЧислКод  Число,10,0 неотрицательный.
там где число установлено то считает что этот элемент справочника уже выровнен.
  
Наверх
 
IP записан
 
Inner Join (c)
Junior Member
**
Отсутствует


I Love BaBB 2!

Сообщений: 23
Зарегистрирован: 15. Октября 2008
Пол: Мужской
Re: Использование цикла по перебору справочника в запросе
Ответ #14 - 21. Апреля 2009 :: 07:58
Печать  
Z1 писал(а) 21. Апреля 2009 :: 07:39:
Так если у тебя коды только целые может тебе в подчиненном справочнике завести Новый реквизит
ЧислКод  Число,10,0 неотрицательный.
там где число установлено то считает что этот элемент справочника уже выровнен.


Думаю это того не стоит. Тут основная проблема в общем запросе получить номера строк отсортированной таблицы единиц ОДНОГО товара, и по этим номерам проставить коды элементов этих единиц. Желательно без передачи данных в оперативку и обратно в SQL. Для этого и цикл в теле основного запроса. Ну без цикла - значит без цикла Улыбка
  
Наверх
 
IP записан
 
Переключение на Главную Страницу Страницы: [1] 2 
ОтправитьПечать