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

 
 
Опции темы Поиск в этой теме Опции просмотра
Старый 30.01.2017, 14:15   #1  
Яга1 is offline
Яга1
Участник
 
8 / 10 (1) +
Регистрация: 30.01.2017
Упрямые DataSource не дают построить прайс-лист
Помогите пож-та, у меня есть таблица номенклатур на которую очень редко и вразнобой меняется цена, поэтому решили хранить не прейкурант полностью, а таблицу, что цена на такой-то ItemId меняется с такой-то даты на такую-то (иногда на 0). Неожиданно для себя не удалось справиться с проблемой, как на заданную дату вывести полный прайс номенклатур с ненулевыми ценами на форму.
Сперва думали обойтись одним датасорсом, но никак не удается заставить его выводить только ОДНУ последнюю строку измененной цены, выводятся и все предыдущие. Тогда решили действовать двумя датасорсами (таблица одна и та же)
Первый датасорс выводит на форму ItemId и дату последнего изменения цены на эту номенклатуру
public void init()
{
QueryBuildDatasource qbds;
;
super();

qbds = this.query().dataSourceTable(tableNum(SOPCenaTable));
qbds.addGroupByField(fieldNum(SOPCenaTable, ItemId));
qbds.addOrderByField(fieldNum(SOPCenaTable, ItemId),SortOrder::Ascending);
qbds.addOrderByField(fieldNum(SOPCenaTable, TransDate),SortOrder:: Descending);
qbds.addSelectionField(fieldNum(SOPCenaTable, TransDate), SelectionField::Max);
qbds.addSelectionField(fieldNum(SOPCenaTable, ItemId), SelectionField:: Database);

qbrCenaTransDate=qbds.addRange(fieldNum(SOPCenaTable, TransDate)); //будет ограничен датой поиска

return;
}
А второй датасорс, который должен отобразить цену и остальные подробности, никак не приделать. Если его присоединять без GroupBy, то почему-то вся информация второго датасорса выводятся как пустая.
Попробовали с GroupBy
public void init()
{
QueryBuildDatasource qbds;
;
super();

qbds = this.query().dataSourceTable(tableNum(SOPCenaTableView));
qbds.addGroupByField(fieldNum(SOPCenaTableView, ItemId));
qbds.addGroupByField(fieldNum(SOPCenaTableView, TransDate));

qbds.addSelectionField(fieldNum(SOPCenaTableView, TransDate), SelectionField::Max);
qbds.addSelectionField(fieldNum(SOPCenaTableView, ItemId), SelectionField::Max);
qbds.addSelectionField(fieldNum(SOPCenaTableView, Price), SelectionField::Max);

qbds.addLink(fieldNum(SOPCenaTableView, ItemId),fieldNum(SOPCenaTable, ItemId));
qbds.addLink(fieldNum(SOPCenaTableView, TransDate),fieldNum(SOPCenaTable, TransDate));
//здесь еще хотели добавить проверку, что цена ненулевая
}
Тип связи InnerJoin, чтобы фильтровать ненулевые цены. Но Аксапта не хочет взять только те строки, для которых в первом датасорсе уже найден TransDate, а подтягивает и все предыдущие даты с ценами, а если поглядеть на запрос, так он получается невообразимый, вторая таблица попала в условие Group bу вместе с первой
SELECT FIRSTFAST MAX(TransDate), ItemId FROM SOPCenaTable GROUP BY SOPCenaTable.ItemId, SOPCenaTableView.ItemId, SOPCenaTableView.TransDate ORDER BY SOPCenaTable.ItemId ASC, SOPCenaTable.TransDate DESC WHERE ((Department = N'ВП-52-29')) AND ((TransDate<={ts '2017-01-27 00:00:00.000'})) JOIN FIRSTFAST MAX(TransDate), MAX(ItemIdMAX(Price) FROM SOPCenaTableView WHERE SOPCenaTable.ItemId = SOPCenaTableView.ItemId AND SOPCenaTable.TransDate = SOPCenaTableView.TransDate


при этом при всем в SQL Management Studio запросы построили легко и правильно выдавали прейскурант (здесь немного по-другому названы таблицы)
select *
from Invent
inner join (select Max(TransDate) As mtd, Item as mItem
from Price
WHERE (TransDate <= CONVERT(DATETIME, '2016-09-08 00:00:00', 102))
group by Item)
As td on Invent.Item=mItem

inner join Price as prend on (prend.Item=mItem) and (prend.TransDate=mtd)
where prend.Price >0
order by Invent.Item

Поскажите пожалуйста, как получить форму в Аксапте с прейскурантом на заданную дату, наверное мы действуем неграмотно? Запасные аэродромы, типа вообще не отфильтровывать ненулевые строки, цены выводить dysplay-функциями и т.п. - это все так неудобно

Axapta 2009 MS SQL Server 2008
Старый 30.01.2017, 15:01   #2  
bitter is offline
bitter
Участник
 
15 / 19 (1) ++
Регистрация: 12.04.2015
Можно предварительно собрать данные во временную таблицу и выводить ее в качестве датасорса.
Старый 30.01.2017, 15:12   #3  
Wamr is offline
Wamr
----------------
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
 
1,737 / 858 (32) +++++++
Регистрация: 15.01.2002
Адрес: Москва
Записей в блоге: 7
Вот так можно
X++:
SELECT *
FROM MyPrice P1
WHERE P1.TransDate <= []
AND NOT EXISTS(SELECT 1 FROM MyPrice P2 
WHERE P2.ItemId = P1.ItemId AND P2.TransDate <= [] AND P2.TransDate > P1.TransDate)
добавить ограничения по цене или еще какие на своё усмотрение
Старый 30.01.2017, 15:39   #4  
Яга1 is offline
Яга1
Участник
 
8 / 10 (1) +
Регистрация: 30.01.2017
Пока не понятно. Что такое 1: AND NOT EXISTS(SELECT 1 FROM MyPrice P2
И ведь именно что существуют изменения цен и до и после заданной даты _DATE
Так-то в X++ для любого _ItemId написать бы функцию
SELECT FIRSTONLY MyPrice1
ORDER BY ItemId, TransDate DESC
WHERE MyPrice1.ItemId==_ItemId && MyPrice1.Transdate<=_DATE
потом по цене отфильтровать
Но как бы сделать такой поиск в датасорсе на форме. Даже если Ваш select верный, на форму-то как его засунуть

Последний раз редактировалось Яга1; 30.01.2017 в 15:48.
Старый 30.01.2017, 15:55   #5  
Владимир Максимов is offline
Владимир Максимов
Участник
КОРУС Консалтинг
 
1,654 / 1158 (42) ++++++++
Регистрация: 13.01.2004
Записей в блоге: 3
Вам же Wamr привел пример. Этот запрос можно реализовать в Query. Не пробовали запускать в SQL? Будет возвращать то, что нужно, даже если есть цены и после _DAET

Может, в таком виде будет нагляднее

X++:
SELECT *
FROM MyPrice P1
WHERE P1.TransDate <= _DATE
      AND NOT EXISTS(SELECT 1 FROM MyPrice P2 
                     WHERE P2.ItemId        = P1.ItemId 
                           AND P2.TransDate <= _DATE 
                           AND P2.TransDate > P1.TransDate)
1 - это константа. Число 1 Надо понимать буквально. Для подзапроса Exists не имеет значения, что именно он вернет. Важен сам факт наличия записи, а не ее содержимое. Поэтому и ставят константу. Хотя "ветераны программирования" предпочитают символ "x" по привычке. Вероятно, потому, что 1 символ - это 1 байт (ну, или 2 для UNICODE). А одно число - это 4 байта. Привычка экономить на всем
__________________
- Может, я как-то неправильно живу?!
- Отчего же? Правильно. Только зря...
За это сообщение автора поблагодарили: Товарищ ♂uatr (1).
Старый 31.01.2017, 09:09   #6  
dech is offline
dech
Участник
Аватар для dech
Самостоятельные клиенты AX
 
643 / 347 (13) ++++++
Регистрация: 25.06.2009
Адрес: Омск
Записей в блоге: 3
Цитата:
Сообщение от Владимир Максимов Посмотреть сообщение
Вероятно, потому, что 1 символ - это 1 байт (ну, или 2 для UNICODE). А одно число - это 4 байта. Привычка экономить на всем
А как же ноль в конце строки? для юникода будут те же 4 байта. :-)
А с числами обычно быстрее работается. Но в данном случае разница в пару тактов процессора.
__________________
// no comments
Старый 31.01.2017, 10:34   #7  
Яга1 is offline
Яга1
Участник
 
8 / 10 (1) +
Регистрация: 30.01.2017
Здравствуйте! Запрос безусловно правильный, но не удается дойти до победного
В форме в executeQuery получается запрос
SELECT FIRSTFAST * FROM SOPCenaTable
ORDER BY SOPCenaTable.ItemId ASC, SOPCenaTable.TransDate DESC
WHERE ((TransDate<={ts '2016-09-01 00:00:00.000'}))
NOTEXISTS JOIN FIRSTFAST * FROM SOPCenaTableView
WHERE SOPCenaTable.ItemId = SOPCenaTableView.ItemId
AND ((((SOPCenaTable.TransDate<SOPCenaTableView.TransDate))
AND ((SOPCenaTableView.TransDate<={ts '2016-09-01 00:00:00.000'}))))

Проблема с AND ((SOPCenaTableView.TransDate<={ts '2016-09-01 00:00:00.000'}))))
это условие не отрабатывает
Первое условие ((TransDate<={ts '2016-09-01 00:00:00.000'})) я строю как
qbrCena1TransDate.value( date2str(datenull(),123,2,2,2,2,4)+ ".." +date2str(_DATE,123,2,2,2,2,4) ); и оно работает нормально
А второе как qbrCena2TransDate.value('((SOPCenaTable.TransDate<SOPCenaTableView.TransDate)) AND ((SOPCenaTableView.TransDate<='
+sqlSystem.sqlLiteral(_DATE)
+'))');
и датовая константа в запросе получается вроде похожа на правильную, но фильтрация по ней не происходит. Проверяли, заменяя NotExists Join на Inner Join
Учитываются строки с более поздними датами

Может быть подскажете как справиться с этой проблемой?
Возможно дело в скобочках?

Последний раз редактировалось Яга1; 31.01.2017 в 10:55.
Старый 30.01.2017, 15:56   #8  
Яга1 is offline
Яга1
Участник
 
8 / 10 (1) +
Регистрация: 30.01.2017
Кажется дошло! Спасибо большое, пойду пробовать
Старый 31.01.2017, 10:53   #9  
dech is offline
dech
Участник
Аватар для dech
Самостоятельные клиенты AX
 
643 / 347 (13) ++++++
Регистрация: 25.06.2009
Адрес: Омск
Записей в блоге: 3
X++:
qbrCena1TransDate.value(queryRange(dateNull(), SOPCenaDoc.TransDate));

qbrCena2TransDate.value(queryRange(SOPCenaTable.TransDate + 1, dateNull()));
qbrCena2TransDate.value(queryRange(dateNull(), SOPCenaDoc.TransDate));
__________________
// no comments
Старый 31.01.2017, 11:15   #10  
Яга1 is offline
Яга1
Участник
 
8 / 10 (1) +
Регистрация: 30.01.2017
1)qbrCena2TransDate.value(queryRange(dateNull(), SOPCenaDoc.TransDate)) вообще убивает предыдущее условие, остается только ((TransDate<={ts '2017-01-27 00:00:00.000'})), а надо AND


2)qbrCena2TransDate.value(queryRange(SOPCenaTable.TransDate + 1, dateNull()));
в запросе превращается в ((TransDate>={ts '1900-01-02 00:00:00.000'}))
Старый 31.01.2017, 11:57   #11  
dech is offline
dech
Участник
Аватар для dech
Самостоятельные клиенты AX
 
643 / 347 (13) ++++++
Регистрация: 25.06.2009
Адрес: Омск
Записей в блоге: 3
Цитата:
Сообщение от Яга1 Посмотреть сообщение
1)qbrCena2TransDate.value(queryRange(dateNull(), SOPCenaDoc.TransDate)) вообще убивает предыдущее условие, остается только ((TransDate<={ts '2017-01-27 00:00:00.000'})), а надо AND


2)qbrCena2TransDate.value(queryRange(SOPCenaTable.TransDate + 1, dateNull()));
в запросе превращается в ((TransDate>={ts '1900-01-02 00:00:00.000'}))
Надо просто новый QueryBuildRange добавить
X++:
qbrCena2TransDate.value('(SOPCenaTable.TransDate < SOPCenaTableView.TransDate)')
qbrCenaTableTransDate = qbds.addRange(fieldNum(SOPCenaTableView, TransDate));
qbrCenaTableTransDate.value(queryRange(datenull(), _DATE));
где qbds - ваш датасорс SOPCenaTableView
__________________
// no comments
Старый 31.01.2017, 12:37   #12  
Яга1 is offline
Яга1
Участник
 
8 / 10 (1) +
Регистрация: 30.01.2017
Тогда условия связались по OR:
(((SOPCenaTable.TransDate < SOPCenaTableView.TransDate)) OR (TransDate<={ts '2016-09-01 00:00:00.000'}))
Старый 31.01.2017, 23:01   #13  
AlGol is offline
AlGol
Участник
 
277 / 93 (4) ++++
Регистрация: 24.12.2001
Адрес: Тверь.
Цитата:
решили хранить не прейкурант полностью, а таблицу, что цена на такой-то ItemId меняется с такой-то даты на такую-то (иногда на 0).
Может проще будет доработать таблицу с ценами до полноценной реализации модели ValidFrom-ValidTo?
Добавить поле даты окончания срока действия цены ValidTo, заполнять его по умолчанию максимальной датой, а при создании строки с последующей датой заполнять его соответстующим значением окончания срока действия.

Тогда запросы по актуальным ценам упростятся до
[дата цены]>=ValidFrom AND [дата цены] <= ValidTo.
__________________
Ален ноби, ностра алис.
Что означает - если один человек построил, другой завсегда разобрать может.
Старый 31.01.2017, 11:10   #14  
Wamr is offline
Wamr
----------------
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
 
1,737 / 858 (32) +++++++
Регистрация: 15.01.2002
Адрес: Москва
Записей в блоге: 7
X++:
qbrCena2TransDate.value('((SOPCenaTable.TransDate<SOPCenaTableView.TransDate) && (SOPCenaTableView.TransDate<='+date2StrXpp(_DATE)+'))');

Последний раз редактировалось Wamr; 31.01.2017 в 11:14.
Старый 31.01.2017, 11:21   #15  
Яга1 is offline
Яга1
Участник
 
8 / 10 (1) +
Регистрация: 30.01.2017
qbrCena2TransDate.value('((SOPCenaTable.TransDate<SOPCenaTableView.TransDate) && (SOPCenaTableView.TransDate<='+date2StrXpp(_DATE)+'))');
в запросе превратилось в
((((SOPCenaTable.TransDate<SOPCenaTableView.TransDate) && (SOPCenaTableView.TransDate<=01\09\2016))))
здесь AND написано не так и дата тоже, но условие почему-то сработало
это не случайность? огромное спасибо!
Старый 01.02.2017, 14:51   #16  
dech is offline
dech
Участник
Аватар для dech
Самостоятельные клиенты AX
 
643 / 347 (13) ++++++
Регистрация: 25.06.2009
Адрес: Омск
Записей в блоге: 3
Цитата:
Сообщение от Яга1 Посмотреть сообщение
Тогда условия связались по OR:
(((SOPCenaTable.TransDate < SOPCenaTableView.TransDate)) OR (TransDate<={ts '2016-09-01 00:00:00.000'}))
Да, действительно, подзабыл уже)))
Надо через Complex expressions реализовать.
Или вот еще тема: Advanced query range value expressions
Цитата:
Сообщение от Яга1 Посмотреть сообщение
Неожиданно для себя не удалось справиться с проблемой, как на заданную дату вывести полный прайс номенклатур с ненулевыми ценами на форму.
Сперва думали обойтись одним датасорсом, но никак не удается заставить его выводить только ОДНУ последнюю строку измененной цены, выводятся и все предыдущие.
Вот мне интересно, вы хотите на форму полный прайс вывести или только ОДНУ последнюю строку?
__________________
// no comments

Последний раз редактировалось dech; 01.02.2017 в 14:59.
 

Похожие темы
Тема Автор Раздел Ответов Посл. сообщение
dynamicsaxhints: Query datasource FirstOnly property Blog bot DAX Blogs 0 22.03.2016 09:11
dax 2012 прайс лист? bender DAX: Функционал 15 12.03.2014 13:53
C# and AX Development: Updating the caller Form/DataSource Blog bot DAX Blogs 0 18.07.2009 02:28
Заполнение DataSource из постоянной и временной таблиц m_ax DAX: Программирование 2 21.06.2007 13:08
Прайс-лист и цена реализации NIMERE DAX: Функционал 0 26.03.2004 15:07

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

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

Рейтинг@Mail.ru
Часовой пояс GMT +3, время: 08:44.
Powered by vBulletin® v3.8.5. Перевод: zCarot
Контактная информация, Реклама.