Имя: Пароль:
1C
1C 7.7
v7: помогите запрос по 1с++
0 Loko
 
24.09.14
04:41
всем привет!

есть внешняя БД. подключаюсь к ней из 1с7. нужно выбрать список товаров,   с определенным списком кодов (кодов бывает от 1000 до 2000 примерно).

пробую через уложить список, предварительно добавив в список значений все коды - выходит пустая таблица.
|SELECT *
|FROM PriceList
|WHERE
|KodTovar IN (SELECT Val FROM #Коды)";

пробовал в строку перечислить все коды (KodTovar IN #Коды) но там строка огромного размера - не получается.

в 8-ке просто через массив делается. а как быть в 7-ке?
1 МастерВопросов
 
24.09.14
05:03
(0) если стоит 1cPP.dll, то УложитьСписок, там же в мануале всё написано
2 Loko
 
24.09.14
05:08
да, я так и пробовал (написал же). не получается.
3 МастерВопросов
 
24.09.14
05:09
Отбор по списку или группе
Для таких случаев у объекта ODBCRecordset есть метод
УложитьСписокОбъектов(Список, Таблица, ВидСправочника) и
УложитьСписокОбъектов13(Список, Таблица)
Список – это список или группа. После  выполнения этого метода появляется таблица с именем Таблица и колонками Val, IsFolder
Однако не стоит злоупотреблять этим методом. Анализируя производительность можно увидеть, что этот метод на группах работает медленно и это совершенно очевидно, т.к. группа может содержать огромное число элементов, которые надо переписать во временную таблицу. ГОРАЗДО эффективней получить список подгрупп входящих в выбранную группу и делать условие по принадлежности к родителю, а не по ID

Пример: Выберем все документы реализации, у которых склад входит в выбранную группу

ТекстЗапроса = "
|SELECT
|    Док.IDDoc as [Док $Документ.Реализация]
|FROM
|    $Документ.Реализация as Док
|WHERE
|    $Док.Склад IN (SELECT Val FROM #Группа)";
RS.УложитьСписокОбъектов(ВыбГруппа, "#Группа", "Склады");

Замечание: Рекомендуется использовать локальные временные таблицы – префикс #. В этом случае не нужно заботиться об уникальности имени таблицы для разных пользователей, а также об их последующем удалении.
В ДБФ версии драйвер сам создает такие таблицы и сам же генерирует им имя.
Можно сделать универсальный способ получения имени таблицы, работающий как в ДБФ, так и в СКЛ:
    ИмяТаблицы="#Группа ";
    Запрос.УложитьСписокОбъектов(СписокРодителей,ИмяТаблицы);
    ТекстЗапроса=" (SELECT Val FROM "+ИмяТаблицы+")";
В случае СКЛ запрос выполнится из таблицы "#Группа", а в случае ДБФ система сгенерит имя и вернет ее в переменную ИмяТаблицы. В случае ДБФ имя временной таблицы выглядит так ‘f6d3b234a56c765f52da’ что, конечно не очень красиво для текста запроса(особенно если его еще и разбирать на ошибки нужно или на дополнения). Можно сделать запрос более красивым и универсальным: для этого воспользуемся методом УстановитьТекстовыйПараметр()
    ИмяТаблицы="#Группа";
    Запрос.УложитьСписокОбъектов(СписокРодителей,ИмяТаблицы);
    Запрос. УстановитьТекстовыйПараметр ("Группа", ИмяТаблицы);
    ТекстЗапроса=" (SELECT Val FROM "+?(ЭтоСКЛ=0,":","#")+"Группа)";
В этом случае если работа происходит в СКЛе то запрос проигнорирует текстовый параметр, а если в ДБФ, то вместо :Группа подставит имя временной таблицы.

Тот же пример, но по списку контрагентов:
ТекстЗапроса = "
|SELECT
|    Док.IDDoc as [Док $Документ.Реализация]
|FROM
|    $Документ.Реализация as Док
|WHERE
|    $Док.Контрагент IN (SELECT Val FROM #Группа)";
RS.УложитьСписокОбъектов13(Список, "#Группа");

Обычно при написании отчетов нужно делать переменные условия: по всем, по элементы, по группе или по списку. Отрабатывать все варианты в каждом отчете – проще застрелиться. И для того, чтобы так не делать мною был разработан класс обертка ЗапросSQL (можно найти на acsent.nm.ru). Суть это класса состоит в макроподстановках

Пример:
Запрос = СоздатьОбъект("ЗапросSQL");
Запрос.ДобавитьУсловие("$Док", "Склад", "", ВыбСклад, "");
Запрос.Текст = "
|SELECT
|    Док.IDDoc as [Док $Документ.Реализация]
|FROM
|    $Документ.Реализация as Док
|WHERE
|    %Склад ";
ТЗ = Запрос.Выполнить();
ТЗ.ВыбратьСтроку();

В зависимости от значения ВыбСклад в запрос встанет условие:
0 = 0 (Пустое значение, по всем)
$Док.Склад = :Склад (Выбран элемент)
$Док.Склад IN (SELECT Val FROM #__Склад)  (Выбрана группа или список)

На небольших списках лучше обойтись без метода «уложения».
Я использую следующую конструкцию
|SELECT
|    Док.IDDoc as Док
|FROM
|    $Документ.Реализация as Док
|WHERE
|    $Док.Склад IN ('     6', '     3', '     2')
|    ";
Где '     6' – внутренний идентификатор элемента справочника «склады».
Получить его можно с помощью метода ЗначениеВСтрокуБД() объекта «MetaDataWork»
    МД=СоздатьОбъект("MetaDataWork");
    Условия ="(";
    Для Н=1 По Список.РазмерСписка() Цикл
        Условия = Условия + "'" + МД.ЗначениеВСтрокуБД(Список.ПолучитьЗначение(Н)) + ?( Н=Список.РазмерСписка(),")","',");
    КонецЦикла;

Этот способ удобен тем, что нет лишней траты времени на выгрузку списка значений во временную таблицу.
4 МастерВопросов
 
24.09.14
05:10
(2) в семерке вместо одномерного массива используется "СписокЗначений"
5 МастерВопросов
 
24.09.14
05:12
6 Loko
 
24.09.14
05:12
(4) да это понятно. я так и сделал: глРС.УложитьСписокОбъектов13(КодыТовара, "#Коды");

где кодыТовара - СписокЗначений.

в (0) посте после запроса я другой способ пробую уже.
7 МастерВопросов
 
24.09.14
05:14
(6) закеж код, где ты СписокЗначений заполняешь.
8 МастерВопросов
 
24.09.14
05:16
"KodTovar IN (SELECT Val FROM #Коды)"

KodTovar - это ссылка, или код товара
в КодыТовара у тебя ссылки, или кода?
9 Loko
 
24.09.14
05:16
(7)
ВыбратьСтроки();
    Пока ПолучитьСтроку()=1 Цикл
        СпрИзг.ИспользоватьВладельца(Товар);                                
        СпрИзг.ВыбратьЭлементы();
        Пока СпрИзг.ПолучитьЭлемент() = 1 Цикл
            Если ПустоеЗначение(СпрИзг.КодФК)=0 Тогда
                КодыТовара.ДобавитьЗначение(СокрЛП(СпрИзг.КодФК));
            КонецЕсли;
        КонецЦикла;                                                  
    КонецЦикла;
10 Loko
 
24.09.14
05:17
(8) коды. текст.
11 МастерВопросов
 
24.09.14
05:21
(10) попробуй тогда такое условие
RTRIM(LTRIM(KodTovar)) IN (SELECT Val FROM #Коды)
12 Loko
 
24.09.14
05:24
(11) не взлетает.
13 МастерВопросов
 
24.09.14
05:27
(12) что не взлетает? Ошибка, или пустой запрос.

Ты бы уже заказал свой реальный запрос, а не огрызок в (0)
14 Loko
 
24.09.14
05:28
один ньюанс: во внешней БД коды эти в формате число, в 1С-ке как строка. переделал на КодыТовара.ДобавитьЗначение(Число(СокрЛП(СпрИзг.КодФК)));

но не идет...
15 Loko
 
24.09.14
05:28
(13) пустая таблица результат
16 ahachack2
 
24.09.14
05:30
на форуме 1cpp вроде писали что для примитивных типов типа строка метод УложитьСписокОбъектов не работает.

Я для базы в формате sql обходил так: делал свою временную таблицу из одной колонки - и заполнял самостоятельно значениями, в основном запросе - обращался к созданной таблице
17 Loko
 
24.09.14
05:33
(16) а можно код как заполняли таблицу?
18 ahachack2
 
24.09.14
05:35
RS=СоздатьОбъект("ODBCRecordset");
RS.Выполнить("drop table #TEMP_INDEX_SVODNIY");
RS.Выполнить("create table #TEMP_INDEX_SVODNIY(S char(11),primary key clustered (S))");

Для сч=1 по СписокИндексов.РазмерСписка() Цикл
RS.Выполнить("insert into #TEMP_INDEX_SVODNIY(S) values('"+СписокИндексов.ПолучитьЗначение(сч)+"')");
КонецЦикла;
Основная теорема систематики: Новые системы плодят новые проблемы.