AXForum  
Вернуться   AXForum > Microsoft Dynamics AX > DAX: Программирование
All
Забыли пароль?
Зарегистрироваться Правила Справка Пользователи Сообщения за день Поиск

 
 
Опции темы Поиск в этой теме Опции просмотра
Старый 12.08.2010, 17:52   #1  
Prophetic is offline
Prophetic
Участник
 
113 / 15 (1) ++
Регистрация: 08.12.2009
select в X++ и список значений в условии where
Здравия всем.

Хочу выбрать записи в X++ из таблицы СustInvoiceTrans с условием InventLocationId, заданном в виде строки 'СКЛАД1,СКЛАД2,СКЛАДN'
Список InventLocationId формируется из параметров запроса -- сделано для того, чтобы пользователь не выбирал InventDimId.
Код приведен ниже, но оператора IN, аналогичного T-SQL я не нашёл.
Что нужно написать в условии where?

X++:
// ... получено из параметров запроса:
str inventLocationId = 'СКЛАД1,СКЛАД2,СКЛАДN'

select custInvoiceTrans 
join InventDim
        where inventDim.inventDimId == CustInvoiceTrans.InventDimId
    join inventLocation
        where inventLocation.InventLocationId == inventDim.InventLocationId &&
              inventLocation.InventLocationId  == .......
Возможно, есть более элегантное решение проблемы?
Старый 12.08.2010, 17:58   #2  
nix0root is offline
nix0root
Участник
 
67 / 16 (1) ++
Регистрация: 17.03.2009
Адрес: МО
Используй queryBuildRange.value(....)
__________________
В подводной охоте главное вдох ...
Старый 12.08.2010, 18:00   #3  
oip is offline
oip
Axapta
Лучший по профессии 2014
 
2,564 / 1416 (53) ++++++++
Регистрация: 28.11.2005
Записей в блоге: 1
Возможно, конечно. Использовать query.
Старый 12.08.2010, 18:00   #4  
Prophetic is offline
Prophetic
Участник
 
113 / 15 (1) ++
Регистрация: 08.12.2009
Цитата:
Сообщение от nix0root Посмотреть сообщение
Используй queryBuildRange.value(....)
Так у меня список InventLocationId Это получается, нужно переводить список InventLocationId в список InventDimId? Хотелось бы более просто решить этот вопрос.
Старый 12.08.2010, 18:04   #5  
lev is offline
lev
Ищущий знания...
Аватар для lev
Oracle
MCBMSS
Axapta Retail User
 
1,723 / 491 (20) +++++++
Регистрация: 18.01.2005
Адрес: Москва
Цитата:
Сообщение от Prophetic Посмотреть сообщение
Так у меня список InventLocationId Это получается, нужно переводить список InventLocationId в список InventDimId? Хотелось бы более просто решить этот вопрос.
не надо ничего переводить никуда

queryBuildRange.value(inventLocationId) и все
__________________
"Страх перед возможностью ошибки не должен отвращать нас от поисков истины." (с)
С Уважением,
Елизаров Артем
Старый 12.08.2010, 18:05   #6  
lev is offline
lev
Ищущий знания...
Аватар для lev
Oracle
MCBMSS
Axapta Retail User
 
1,723 / 491 (20) +++++++
Регистрация: 18.01.2005
Адрес: Москва
подробнее

X++:
qbdsCustInvoceTrans = query.addDataSource(tablenum(CustInvoiceTrans));
qbdsInventDim = qbdsCustInvoceTrans .addDataSource(tablenum(InventDim));
qbdsInventDim .relation(true);
qbdsInventDim.addRange(fieldNum(InventDim, InventLocationId)).value(inventLocationId);
__________________
"Страх перед возможностью ошибки не должен отвращать нас от поисков истины." (с)
С Уважением,
Елизаров Артем
За это сообщение автора поблагодарили: Prophetic (1).
Старый 13.08.2010, 09:23   #7  
Prophetic is offline
Prophetic
Участник
 
113 / 15 (1) ++
Регистрация: 08.12.2009
Цитата:
Сообщение от lev Посмотреть сообщение
подробнее

X++:
qbdsCustInvoceTrans = query.addDataSource(tablenum(CustInvoiceTrans));
qbdsInventDim = qbdsCustInvoceTrans .addDataSource(tablenum(InventDim));
qbdsInventDim .relation(true);
qbdsInventDim.addRange(fieldNum(InventDim, InventLocationId)).value(inventLocationId);

Да, это решит проблему, благодарю. Однако, вопрос в том, что я пытаюсь модифицировать класс CustTransStatistics, в котором уже всё завязано на простую таблицу. Просто очень не хочется ВСЁ переписывать.
Может быть есть ещё другой способ отфильтровать по складам?
Старый 13.08.2010, 09:39   #8  
Gustav is offline
Gustav
Moderator
Аватар для Gustav
SAP
Лучший по профессии 2009
 
1,858 / 1152 (42) ++++++++
Регистрация: 24.01.2006
Адрес: Санкт-Петербург
Записей в блоге: 19
У меня вот здесь Можно ли в SELECT использовать критерия вида "10..20" было некоторое подобие IN для таких случаев недлинных списков. Во всяком случае, визуально в составе select'а выглядит вполне удовлетворительно. Может, подойдёт приемчик?
За это сообщение автора поблагодарили: mazzy (2), lev (2), S.Kuskov (3), Prophetic (1).
Старый 13.08.2010, 10:36   #9  
nix0root is offline
nix0root
Участник
 
67 / 16 (1) ++
Регистрация: 17.03.2009
Адрес: МО
Как вариант используйте прямой запрос к базе с IN-ми и LIKE-ми )
__________________
В подводной охоте главное вдох ...
За это сообщение автора поблагодарили: S.Kuskov (-1), Prophetic (1).
Старый 13.08.2010, 10:42   #10  
Prophetic is offline
Prophetic
Участник
 
113 / 15 (1) ++
Регистрация: 08.12.2009
Цитата:
Сообщение от Gustav Посмотреть сообщение
У меня вот здесь Можно ли в SELECT использовать критерия вида "10..20" было некоторое подобие IN для таких случаев недлинных списков. Во всяком случае, визуально в составе select'а выглядит вполне удовлетворительно. Может, подойдёт приемчик?
Приём интересный, но не сработал: "Использование контейнеров и полей с неограниченными строками (текстом) в выражении WHERE не допускается.". Ибо у меня значения критериев не руками прописываются, а получаются из формы в виде строки.

Последний раз редактировалось Prophetic; 13.08.2010 в 10:45.
Старый 13.08.2010, 11:04   #11  
S.Kuskov is offline
S.Kuskov
Участник
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
 
3,440 / 1775 (66) ++++++++
Регистрация: 28.04.2007
Адрес: Калуга
Цитата:
Сообщение от nix0root Посмотреть сообщение
Как вариант используйте прямой запрос к базе с IN-ми и LIKE-ми )
Нет. Не нужно так поступать.
Цитата:
Сообщение от Prophetic Посмотреть сообщение
Приём интересный, но не сработал: "Использование контейнеров и полей с неограниченными строками (текстом) в выражении WHERE не допускается.". Ибо у меня значения критериев не руками прописываются, а получаются из формы в виде строки.
Просто используйте вместо типа str, какой-нибудь расширенный тип данных, ни или на крайний случай пишите "str 30", т.е еграничте длину типа
Старый 13.08.2010, 11:16   #12  
Prophetic is offline
Prophetic
Участник
 
113 / 15 (1) ++
Регистрация: 08.12.2009
Цитата:
Сообщение от S.Kuskov Посмотреть сообщение
Нет. Не нужно так поступать.

Просто используйте вместо типа str, какой-нибудь расширенный тип данных, ни или на крайний случай пишите "str 30", т.е еграничте длину типа
В том интересном приёме обрабатывается контейнер, поэтому строку со списком я перевожу в контейнер, и получаю вот такой код:

X++:
inventLocationRange = str2con_RU(inventLocationId, ',');
while select custInvoiceTrans where custInvoiceTrans.InvoiceDate == 01\04\2010
join InventDim
        where inventDim.inventDimId == CustInvoiceTrans.InventDimId &&
              #sqlIn(inventDim.InventLocationId,inventLocationRange)
Получается, что компилятор не видит, что контейнер то используется в макросе, а не непосредственно в запросе.
Старый 13.08.2010, 11:48   #13  
Gustav is offline
Gustav
Moderator
Аватар для Gustav
SAP
Лучший по профессии 2009
 
1,858 / 1152 (42) ++++++++
Регистрация: 24.01.2006
Адрес: Санкт-Петербург
Записей в блоге: 19
"А, пожалуйста!" (с) "О чём говорят мужчины"
А если не создавать отдельную переменную-контейнер и вставить вызов str2con_RU прямо в параметр макроса? У меня на 3.0 SP4 прокатило:
X++:
static void test_SQL_Imitation_2(Args _args)
{
    #macrolib.SQL_Imitation

    Dialog          dialog;
    DialogField     dialogField;
    InventLocation  inventLocation;
    ;

    dialog = new Dialog('Тест имитации SQL IN');
    dialogField = dialog.addFieldValue(Types::String, 
                                       'СКЛАД1,СКЛАД2,СКЛАДN',
                                       'Введите значения через запятую (не более 10)');
    if (dialog.run())
    {
        while select inventLocation
            where #sqlIn( inventLocation.InventLocationId, str2con_RU(dialogField.value(),',') )
        {
            info (inventLocation.InventLocationId);
        }
    }
}
Старый 13.08.2010, 11:50   #14  
online
Dron AKA andy
Moderator
 
944 / 253 (10) ++++++
Регистрация: 27.03.2002
Адрес: Москва
Цитата:
Сообщение от Gustav Посмотреть сообщение
У меня вот здесь Можно ли в SELECT использовать критерия вида "10..20" было некоторое подобие IN для таких случаев недлинных списков. Во всяком случае, визуально в составе select'а выглядит вполне удовлетворительно. Может, подойдёт приемчик?
Цитата:
Сообщение от Prophetic Посмотреть сообщение
Приём интересный, но не сработал: "Использование контейнеров и полей с неограниченными строками (текстом) в выражении WHERE не допускается.". Ибо у меня значения критериев не руками прописываются, а получаются из формы в виде строки.
Вообще-то сообщение компилятора вполне справедливо, т.к. в запросе через макрос подставляется использование контейнера. Так что такой вариант не подходит...
__________________
Андрей.
Старый 13.08.2010, 11:59   #15  
Prophetic is offline
Prophetic
Участник
 
113 / 15 (1) ++
Регистрация: 08.12.2009
Цитата:
Сообщение от Gustav Посмотреть сообщение
"А, пожалуйста!" (с) "О чём говорят мужчины"
А если не создавать отдельную переменную-контейнер и вставить вызов str2con_RU прямо в параметр макроса? У меня на 3.0 SP4 прокатило:
X++:
static void test_SQL_Imitation_2(Args _args)
{
    #macrolib.SQL_Imitation

    Dialog          dialog;
    DialogField     dialogField;
    InventLocation  inventLocation;
    ;

    dialog = new Dialog('Тест имитации SQL IN');
    dialogField = dialog.addFieldValue(Types::String, 
                                       'СКЛАД1,СКЛАД2,СКЛАДN',
                                       'Введите значения через запятую (не более 10)');
    if (dialog.run())
    {
        while select inventLocation
            where #sqlIn( inventLocation.InventLocationId, str2con_RU(dialogField.value(),',') )
        {
            info (inventLocation.InventLocationId);
        }
    }
}
Действительно, сработало. Огромнейшая благодарность.
Хотя неясно, почему компилятор не проверил тип возвращаемого значения.
Старый 13.08.2010, 11:59   #16  
S.Kuskov is offline
S.Kuskov
Участник
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
 
3,440 / 1775 (66) ++++++++
Регистрация: 28.04.2007
Адрес: Калуга
Позволю себе немного модифицировать макрос SqlIn. Идея таже, но реализация не через контейнер, а через масив. Плюс ещё добавлена проверка выхода за границы масива.
X++:
static void Job_SQL_IN(Args _args)
{
    #LOCALMACRO.sqlIn
    (
    ((%3 <= 1) && (%1 == %2[1])) ||
    ((%3 <= 2) && (%1 == %2[2])) ||
    ((%3 <= 3) && (%1 == %2[3])) ||
    ((%3 <= 4) && (%1 == %2[4])) ||
    ((%3 <= 5) && (%1 == %2[5])) ||
    ((%3 <= 6) && (%1 == %2[6])) ||
    ((%3 <= 7) && (%1 == %2[7])) ||
    ((%3 <= 8) && (%1 == %2[8])) ||
    ((%3 <= 9) && (%1 == %2[9])) ||
    ((%3 <= 10) && (%1 == %2[10]))
    )
    #ENDMACRO

    custInvoiceTrans custInvoiceTrans;
    InventDim InventDim;
    inventLocationId inventLocationId;
    container inventLocationCon;
    int n;
    inventLocationId inventLocationArr[10];
    ;

//    inventLocationId = ...; 
    inventLocationCon = str2con_RU(inventLocationId, ',');

    for (n = 1; n <= conlen(inventLocationCon); n++)
    {
        inventLocationArr[n] = conpeek(inventLocationCon, n);
    }
    n--;

    while select custInvoiceTrans where custInvoiceTrans.InvoiceDate == 01\04\2010
    join InventDim
        where inventDim.inventDimId == CustInvoiceTrans.InventDimId &&
              #sqlIn(inventDim.InventLocationId, inventLocationArr, n)
    {
       //...
    }
}
P.S.: А вообще всё это извращения какие-то. Везде где это возможно лучше используйте Query.
За это сообщение автора поблагодарили: lev (1).
Старый 13.08.2010, 12:18   #17  
Gustav is offline
Gustav
Moderator
Аватар для Gustav
SAP
Лучший по профессии 2009
 
1,858 / 1152 (42) ++++++++
Регистрация: 24.01.2006
Адрес: Санкт-Петербург
Записей в блоге: 19
В общем, компилятор обижается, когда параметром макроса выступает переменная конкретного "плохого" типа (контейнер или безразмерная строка). Если же переменную заменить на вызов функции, пусть даже и возвращающей "плохой" тип, то всё получается:
X++:
static void test_SQL_Imitation_3(Args _args)
{
    #macrolib.SQL_Imitation

    InventLocation  inventLocation;

    container c = ['СКЛАД1','СКЛАД2','СКЛАДN']; // не работает

    container c() // работает
    {
        return ['СКЛАД1','СКЛАД2','СКЛАДN'];
    }
    ;

    while select inventLocation
        //where #sqlIn( inventLocation.InventLocationId, c   ) // не работает
          where #sqlIn( inventLocation.InventLocationId, c() ) // работает
    {
        info (inventLocation.InventLocationId);
    }
}
Старый 13.08.2010, 12:28   #18  
Prophetic is offline
Prophetic
Участник
 
113 / 15 (1) ++
Регистрация: 08.12.2009
Цитата:
Сообщение от S.Kuskov Посмотреть сообщение
Позволю себе немного модифицировать макрос SqlIn. Идея таже, но реализация не через контейнер, а через масив. Плюс ещё добавлена проверка выхода за границы масива.
P.S.: А вообще всё это извращения какие-то. Везде где это возможно лучше используйте Query.
Тоже неплохо, благодарю. Согласен, что извращения, но все же иногда надо.
Старый 13.08.2010, 14:02   #19  
Владимир Максимов is offline
Владимир Максимов
Участник
КОРУС Консалтинг
 
1,701 / 1195 (43) ++++++++
Регистрация: 13.01.2004
Записей в блоге: 3
Цитата:
Сообщение от Prophetic Посмотреть сообщение
Однако, вопрос в том, что я пытаюсь модифицировать класс CustTransStatistics, в котором уже всё завязано на простую таблицу. Просто очень не хочется ВСЁ переписывать.
Может быть есть ещё другой способ отфильтровать по складам?
А почему не сделать напрашивающееся решение в виде цикла в котором по очереди передаешь ОДНО значение?

Ну, разбиваешь строку на элементы в тот же массив, потом цикл по массиву и вызов метода, куда в качестве параметра передаешь значение очередного элемента массива.

Не надо никаких переделок на Query и "танцев с бубном" в виде макросов. Все просто и понятно. Насчет скорости... Ну, это надо посмотреть. Тут все зависит от того, сколько значений будет в передаваемой строке
Старый 13.08.2010, 17:02   #20  
Prophetic is offline
Prophetic
Участник
 
113 / 15 (1) ++
Регистрация: 08.12.2009
Цитата:
Сообщение от Владимир Максимов Посмотреть сообщение
А почему не сделать напрашивающееся решение в виде цикла в котором по очереди передаешь ОДНО значение?

Ну, разбиваешь строку на элементы в тот же массив, потом цикл по массиву и вызов метода, куда в качестве параметра передаешь значение очередного элемента массива.

Не надо никаких переделок на Query и "танцев с бубном" в виде макросов. Все просто и понятно. Насчет скорости... Ну, это надо посмотреть. Тут все зависит от того, сколько значений будет в передаваемой строке
Gustav предложил отличное решение, которое полностью решило мою проблему. Если писать "с нуля", то конечно же, Query гораздо правильнее. В этом случае мне просто не хотелось менять уже существующий код.
Теги
select, where

 

Похожие темы
Тема Автор Раздел Ответов Посл. сообщение
QueryBuildRange в select.. where propeller DAX: Программирование 11 30.09.2008 13:35
Разница NotInTTS и Found Logger DAX: База знаний и проекты 6 18.09.2008 12:35
Ошибка при старте АОСа zZ_TOP_Zz DAX: Администрирование 4 11.09.2008 16:08
Вопрос про Demand Planner slava09 DAX: Функционал 4 25.09.2006 11:43
select * where ... Perc DAX: Программирование 10 06.07.2005 12:31

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход

Рейтинг@Mail.ru
Часовой пояс GMT +3, время: 10:26.