Имя: Пароль:
1C
 
v7: Проблемы с "внешней" функцией в запросе
0 Umnov
 
26.03.10
20:55
Не могу понять почему не происходит вызов функции
При прохождении под отладчиком туда как будто вообще не попадает и как результат СуммаНом пустое

Перем ЗакупТипЦен, ВалютаРубли;


Функция ВернутьСумму(Цена, Валюта, КолВо)
   
   возврат глПересчет(Цена*КолВо, Валюта, ТекущаяДата(), ВалютаРубли, ТекущаяДата());

КонецФункции    


//*******************************************
// Процедура генерации запроса НоменклатураВГруппе.
//
Процедура НоменклатураВГруппе()
   Перем Запрос, ТекстЗапроса, Таб;
   //Создание объекта типа Запрос
   Запрос = СоздатьОбъект("Запрос");
   ТекстЗапроса =
   "//{{ЗАПРОС(НоменклатураВГруппе)
   |Номенклатура = Регистр.ОстаткиТМЦ.Номенклатура, Справочник.Цены.Владелец, Регистр.Заказы.Номенклатура, Регистр.РезервыТМЦ.Номенклатура;
   |ОстатокНом = Регистр.ОстаткиТМЦ.Количество;
   |ТранзитНом = Регистр.Заказы.КоличествоПриход;
   |РезервНом = Регистр.РезервыТМЦ.Количество;
   |ТипЦен = Справочник.Цены.ТипЦен;
   |Цена = Справочник.Цены.Цена;
   |Валюта = Справочник.Цены.Валюта;
   |Индекс = Регистр.ОстаткиТМЦ.Склад.Индекс;
   |Функция Остаток = КонОст(ОстатокНом);
   |Функция Транзит = КонОст(ТранзитНом);
   |Функция Резерв = КонОст(РезервНом);
   |Функция СуммаНом = Сумма(ВернутьСумму(Цена,Валюта,ОстатокНом));
   |Группировка Номенклатура без групп;
   |Условие(Номенклатура в ВыбНоменклатура);
   |Условие(ТипЦен = ЗакупТипЦен);
   |"//}}ЗАПРОС
   ;
   // Если ошибка в запросе, то выход из процедуры
   Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
       Возврат;
   КонецЕсли;

   // Подготовка к заполнению выходных форм данными запроса
   Таб = СоздатьОбъект("Таблица");
   Таб.ИсходнаяТаблица("НоменклатураВГруппе");
   // Заполнение полей "Заголовок"
   Таб.ВывестиСекцию("Заголовок");
   Состояние("Заполнение выходной таблицы...");
   Таб.Опции(0, 0, Таб.ВысотаТаблицы(), 0);
   Пока Запрос.Группировка(1) = 1 Цикл
       // Заполнение полей Номенклатура
       Таб.ВывестиСекцию("Номенклатура");
   КонецЦикла;
   // Заполнение полей "Итого"
   Таб.ВывестиСекцию("Итого");
   // Вывод заполненной формы
   Таб.ТолькоПросмотр(1);
   Таб.Показать("НоменклатураВГруппе", "");
КонецПроцедуры


Процедура ПриОткрытии()

   СпрТипыЦен = СоздатьОбъект("Справочник.ТипыЦен");
   СпрТипыЦен.НайтиПоНаименованию("Базовые");
   ЗакупТипЦен = СпрТипыЦен.ТекущийЭлемент();
   
   СпрВалюты = СоздатьОбъект("Справочник.Валюты");
   СпрВалюты.НайтиПоКоду(810,1);
   ВалютаРубли = СпрВалюты.ТекущийЭлемент();
   
КонецПроцедуры
1 dk
 
26.03.10
20:58
1. отладчик в ф-ции из запроса не заходит
2. что там возвращает глПересчет?
2 dk
 
26.03.10
20:59
чтобы убедиться, что заходит добавь сообщить в ф-цию
3 Umnov
 
26.03.10
21:03
спасибо... не знал что не заходит
поставил сообщить - все норм
проблема с данными видимо - буду вычислять сейчас
4 Umnov
 
26.03.10
21:09
Проблема найдена
   |ОстатокНом = Регистр.ОстаткиТМЦ.Количество; тут 0
вот тут
  |Функция Остаток = КонОст(ОстатокНом);
нужное значение ... но вызов функции в таком виде
   |Функция СуммаНом = Сумма(ВернутьСумму(Цена,Валюта,ОстатокНом));
выдает
Функция СуммаНом = Сумма(ВернутьСумму(Цена,Валюта,Остаток <<?>> ));
Запрос[13] : Ошибка в выражении 'Остаток'
((((
есть ли решение?
5 dk
 
26.03.10
21:13
не, с такими извратами в запросах - это к Ёпрст
6 Umnov
 
26.03.10
21:20
просто если писать просто в SQL то все просто и ясно а вот с 1с так не везет)
7 NS
 
26.03.10
21:20
нет решения. У тебя разные переменные запроса описывают разные структуры - регистр и справочник.
8 NS
 
26.03.10
21:23
что-то я заврался.
|Функция СуммаНом = Сумма(ВернутьСумму(Цена,Валюта,ОстатокНом));
выдает
Функция СуммаНом = Сумма(ВернутьСумму(Цена,Валюта,Остаток <<?>> ));
Каким образом на "ОстатокНом" ругается как на "остаток"?
9 NS
 
26.03.10
21:25
Функция СуммаНом = Сумма(ВернутьСумму(Цена,Валюта,Запрос.Остаток));
10 Umnov
 
26.03.10
21:27
нет
ошибся конечно ошибку выдает вызов
Функция СуммаНом = Сумма(ВернутьСумму(Цена,Валюта,Запрос.Остаток));
11 Umnov
 
26.03.10
21:30
т.е. как я понял невозможно в функции обратиться к значению которую возвращает другая функция
12 Cthulhu
 
26.03.10
22:37
//(4),(11): возможно. попробуй:
|Функция СуммаНом = Сумма(ВернутьСумму(Цена,Валюта,Запрос.Остаток));
13 Cthulhu
 
26.03.10
22:41
ЗЫ: кстати, подобным "финтом ушами" построил запрос, выдающий в результате список контрагентов + первых(!)документов, двинувших регистр... ))
14 Umnov
 
27.03.10
07:32
не спасает т сожалению....
при вызове конструктора выдает

Функция СуммаНом = Сумма(ВернутьСумму(Цена,Валюта,Запрос.Остаток <<?>> ));
Запрос[13] : Ошибка в выражении 'Запрос'
Ошибок - 1, Предупреждений - 0.

если просто выполнить ошибок нет но Запрос.Остаток  = 0 ... хотя не 0 оно(

видимо красиво не выйдет писать ... придется как всегда - через ... .
15 VladZ
 
27.03.10
08:15
Ценой можно озадачится на этапе вывода информации.
16 Umnov
 
27.03.10
08:37
(15) безусловно.... но было бы красивей все в запросе....
17 Umnov
 
27.03.10
08:40
просто с Цена,Валюта проблем не возникает... все проблемы с Остаток )))
который является результатом тоже фанкции
18 VladZ
 
27.03.10
09:50
(16) "Красивее" - не тот критерий, на который стоило бы ориентироваться..  :)
19 Cthulhu
 
27.03.10
11:51
(14): головой думай. И ставь в текст вместо Запрос имя твоей переменной (типа "Запрос").
если у других работает а у тебя не работает - это вовсе не значит, что у других ошибка в программе из-за которой оно у них работате, это значит что нужно подумать.
20 vcv
 
27.03.10
11:53
(14) Ты выбери что-то одно. Или конструктором писать стандартные, рекомендованные нам свыше запросы, со всеми их ограничениями и недостатками. Или руками писать какие-то запросные извращения.
21 Umnov
 
27.03.10
12:03
(19) а текст выше посмотреть как??? ))))
  Запрос = СоздатьОбъект("Запрос");
(20) ну насчет извращений я бы поспорил.... вот делать все руками - извращение... а запросом на МОЙ взгляд нет... не говорю что это правильно для всех)
22 Umnov
 
27.03.10
12:11
(13) был бы счастлив увидеть кусочег кода)
заранее спасибо
23 vcv
 
27.03.10
13:50
(21) Извращение - имеется в виду конструкция
Функция СуммаНом = Сумма(ВернутьСумму(Цена,Валюта,Запрос.Остаток));
в запросе. Точнее обращение к "Запрос.Остаток". Конструктор не позволяет такую написать. Но руками строчку запроса написать можно. Правда при этом нужно быть готовым к тому, что запрос может начать работать в несколько раз медленнее.
24 Cthulhu
 
27.03.10
15:05
(23): я заюзав внешнюю функцию решил задачу получения запросом списка первых(!!!) документов, двинувших регистр - и сократив время запроса на порядки (перевод: в сотни(!) раз).
просто нужно думать - как и чем пользоваться. для чего. впрочем как и везде.
25 vcv
 
28.03.10
11:20
Поделился бы примером запроса. Эффект "в сотни раз" - на это стоит посмотреть и проанализировать.
26 Cthulhu
 
28.03.10
13:46
(25): а самому не интересно? все ведь штатно.
27 Cthulhu
 
28.03.10
13:49
(24)+: (25): ну может и не в сотни, каюсь. ))) но значительно: на среднем ноуте 65+к записей регистра взаиморасчетов с покупателями лопатит за 5-6 секунд и вылает в результате первые документы с движениями по регистру по 1300+ покупателям.
28 Umnov
 
28.03.10
14:06
(26)аааа  хачу посмотреть!!!!
29 vcv
 
28.03.10
19:01
(27) Ты бы все же поделился. Я тоже достигал с помощью извратов в штатных запросах хороших результатов, но интересен и чужой опыт. Особенно если нахаляву :-)
<РекламаON>Вот, например, моя полезняшка: http://infostart.ru/public/64620/ <РекламаOFF>
Вдруг удастся приложить удачно к одной своей задачке. Хитрый анализ взаиморасчетов с аналитическим распределением по поставщикам, номенклатуре и прочим параметрам документов/партий, 20К контрагентов, полмиллиона движений в регистре. Минуты три запрос выполняется и минут 30 обработка результатов запроса. Есть слабая надежда, что приснится ночью идея, как часть обработки результатов запроса перенести в запрос, что бы SQL работал, а не клиент.
30 Cthulhu
 
28.03.10
19:17
(29): "504 Gateway Time-out"
31 Cthulhu
 
28.03.10
19:18
// Да все просто.
// --- список обработанных покупателей и счетчик записей запроса - переменные модуля:
Перем тПокупСЗ,кЗапросНомерЗаписи;
// --- внешняя функция, используемая в запросе:
Функция ФункФлЕсть(тПокуп)
   Перем флЕсть; флЕсть=тПокупСЗ.НайтиЗначение(тПокуп);
   кЗапросНомерЗаписи=кЗапросНомерЗаписи+1;    // чтобы знать - сколько там записей из регистра перелопачено...
   //Состояние("Зап."+кЗапросНомерЗаписи+" / Покуп="+тПокупСЗ.РазмерСписка()+" ...");    // ... и чтобы не скучно было
   //Если флЕсть=0 Тогда тПокупСЗ.ДобавитьЗначение(тПокуп); Сообщить(""+тПокуп+" - добавлен...","i");    // отладка
   //Иначе Сообщить("Покуп."+тПокуп+"="+флЕсть+" - пропуск...",".") КонецЕсли;                            // отладка
   Если флЕсть=0 Тогда тПокупСЗ.ДобавитьЗначение(тПокуп) КонецЕсли; Возврат(флЕсть);
КонецФункции //ФункЕсть
// --- кусок процедуры, получающий запросом список первых документов по контрагентам
// --- из регистра взаиморасчетов с покупателями:
   тПокупСЗ=СоздатьОбъект("СписокЗначений"); кЗапросНомерЗаписи=0;
   тТхт="Период с ВыбНачПериода по ВыбКонПериода;
   |Покуп=Регистр.ВзаиморасчетыПокупателей.Контрагент;
   |тСум=Регистр.ВзаиморасчетыПокупателей.ДолгОсн;
   |Функция ДолгПлюс=Приход(тСум); Функция ДолгМинус=Расход(тСум);
   |Группировка Покуп БЕЗ ГРУПП; Группировка Документ;
   |Функция ФлЕсть=Сумма(ФункФлЕсть(Покуп)); Условие (тВыб.ФлЕсть=0);"; // sic!
   Сообщить("["+ТекущаяДата()+"/"+ТекущееВремя()+"]: Выполнение запроса ...",".");
   тМилиСек=_GetPerformanceCounter();
   тВыб=СоздатьОбъект("Запрос"); Если тВыб.Выполнить(тТхт)=0 Тогда Возврат КонецЕсли;
   тМилиСек=_GetPerformanceCounter()-тМилиСек;
   Сообщить("["+ТекущаяДата()+"/"+ТекущееВремя()+"]: Запрос по "+кЗапросНомерЗаписи
   +" записям регистра выполнен за "+(тМилиСек/1000)+" секунд - выбрано "+тПокупСЗ.РазмерСписка()+" покупателей ...","i");
   тМилиСек=_GetPerformanceCounter(); кЗапросНомерЗаписи=тПокупСЗ.РазмерСписка(); тЗапросНомерЗаписи=0;
   Пока тВыб.Группировка("Покуп")=1 Цикл
       Пока тВыб.Группировка("Документ")=1 Цикл
           тЗапросНомерЗаписи=тЗапросНомерЗаписи+1;
           Состояние("Запрос("+тЗапросНомерЗаписи+"/"+кЗапросНомерЗаписи+"): "+тВыб.Покуп+" / "+тВыб.Докум+" ...");
           Сообщить("   + Выборка: Покуп.="+тВыб.Покуп+" / Докум.="+тВыб.Докум,"");
       КонецЦикла;
   КонецЦикла;
   тМилиСек=_GetPerformanceCounter()-тМилиСек;
   Сообщить("["+ТекущаяДата()+"/"+ТекущееВремя()+"]: Выборка по "+кЗапросНомерЗаписи+" группировкам Запроса выполнена за "+(тМилиСек/1000)+" секунд ...","i");
// как-то так... с бантиками... )))
32 vcv
 
28.03.10
19:59
(30) Как обычно. Инфостарт с переменным успехом борется с пользователями. Ни как не может найти тонкую грань между желаемым (побольше активных пользователей) и своими возможностями это желаемое переварить.
(31) Гм. Элегантненько. Такое мне в голову не приходило. Респект. Кажется вижу, как и свой проблемный отчет ускорить.
33 Umnov
 
29.03.10
20:52
да неплохо только с моей задачей не сходится!
34 vcv
 
30.03.10
09:41
(33) Мне кажется, что в твоем случае, гораздо проще не связываться с функцией, а расценить остатки при выводе отчета.
Или хотя бы убрать из запроса справочник цен. Если в функцию в запросе передавать номенклатуру и остаток, определять цену и считать сумму уже в функции. Для ускорения можно предварительно заполнить таблицу значений ценами и в функции быстро выбирать нужное из ТЗ.
35 Ёпрст
 
гуру
30.03.10
09:51
(0) Функция сумма в останковых регистрах считает только тогда, когда вычисляются другие функции в тексте запроса (исключение - сумма по реквизиту регистра)
Соответственно, при функции КонОст функция сумма будет считать так:

если запрос на начало/конец периодичности сохранения останков, то КонОст ничего не вычисляет, итоги сразу берет из таблички итогов - функция Сумма в запросе ничего не возвращает..
Иначе, конОст берет итоги с ближайшего периода и вычисляет останки конечный остаток как начОст(из таблички итогов)+(Приход-Расход)из таблички движений..
Вот при работе прихода и расхода будет выполнятся функция сумма...

Ежели в тексте запроса добавить другие функции - Приход/расход, то Сумма будет вычисляться при вычислении и этих функций..+ для каждого "движения" регистра.
36 Ёпрст
 
гуру
30.03.10
09:58
+35 хотя в дбф функция конОст будет вычисляться немного по-другому.. и Сумма будет работать всегда, в не зависимости от даты запроса.
Проблемы невозможно решaть нa том же уровне компетентности, нa котором они возникaют. Альберт Эйнштейн