AXForum  
Go Back   AXForum > Microsoft Dynamics AX > DAX: Программирование
All
Forgotten Your Password?
Register Forum Rules FAQ Members List Today's Posts Search

 
 
Thread Tools Search this Thread Display Modes
Old 30.01.2017, 14:15   #1  
Яга1 is offline
Яга1
Участник
 
8 / 10 (1) +
Join Date: 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
Old 30.01.2017, 15:01   #2  
bitter is offline
bitter
Участник
 
15 / 19 (1) ++
Join Date: 12.04.2015
Можно предварительно собрать данные во временную таблицу и выводить ее в качестве датасорса.
Old 30.01.2017, 15:12   #3  
Wamr is offline
Wamr
----------------
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
 
1,737 / 868 (32) +++++++
Join Date: 15.01.2002
Location: Москва
Blog Entries: 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)
добавить ограничения по цене или еще какие на своё усмотрение
Old 30.01.2017, 15:39   #4  
Яга1 is offline
Яга1
Участник
 
8 / 10 (1) +
Join Date: 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 верный, на форму-то как его засунуть

Last edited by Яга1; 30.01.2017 at 15:48.
Old 30.01.2017, 15:55   #5  
Владимир Максимов is offline
Владимир Максимов
Участник
КОРУС Консалтинг
 
1,715 / 1204 (44) ++++++++
Join Date: 13.01.2004
Blog Entries: 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 байта. Привычка экономить на всем
__________________
- Может, я как-то неправильно живу?!
- Отчего же? Правильно. Только зря...
This post has been rated by: Товарищ ♂uatr (1).
Old 30.01.2017, 15:56   #6  
Яга1 is offline
Яга1
Участник
 
8 / 10 (1) +
Join Date: 30.01.2017
Кажется дошло! Спасибо большое, пойду пробовать
Old 31.01.2017, 09:09   #7  
dech is offline
dech
Участник
dech's Avatar
Самостоятельные клиенты AX
 
650 / 352 (13) ++++++
Join Date: 25.06.2009
Location: Омск
Blog Entries: 3
Quote:
Originally Posted by Владимир Максимов View Post
Вероятно, потому, что 1 символ - это 1 байт (ну, или 2 для UNICODE). А одно число - это 4 байта. Привычка экономить на всем
А как же ноль в конце строки? для юникода будут те же 4 байта. :-)
А с числами обычно быстрее работается. Но в данном случае разница в пару тактов процессора.
__________________
// no comments
Old 31.01.2017, 10:34   #8  
Яга1 is offline
Яга1
Участник
 
8 / 10 (1) +
Join Date: 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
Учитываются строки с более поздними датами

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

Last edited by Яга1; 31.01.2017 at 10:55.
Old 31.01.2017, 10:53   #9  
dech is offline
dech
Участник
dech's Avatar
Самостоятельные клиенты AX
 
650 / 352 (13) ++++++
Join Date: 25.06.2009
Location: Омск
Blog Entries: 3
X++:
qbrCena1TransDate.value(queryRange(dateNull(), SOPCenaDoc.TransDate));

qbrCena2TransDate.value(queryRange(SOPCenaTable.TransDate + 1, dateNull()));
qbrCena2TransDate.value(queryRange(dateNull(), SOPCenaDoc.TransDate));
__________________
// no comments
Old 31.01.2017, 11:10   #10  
Wamr is offline
Wamr
----------------
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
 
1,737 / 868 (32) +++++++
Join Date: 15.01.2002
Location: Москва
Blog Entries: 7
X++:
qbrCena2TransDate.value('((SOPCenaTable.TransDate<SOPCenaTableView.TransDate) && (SOPCenaTableView.TransDate<='+date2StrXpp(_DATE)+'))');

Last edited by Wamr; 31.01.2017 at 11:14.
Old 31.01.2017, 11:15   #11  
Яга1 is offline
Яга1
Участник
 
8 / 10 (1) +
Join Date: 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'}))
Old 31.01.2017, 11:21   #12  
Яга1 is offline
Яга1
Участник
 
8 / 10 (1) +
Join Date: 30.01.2017
qbrCena2TransDate.value('((SOPCenaTable.TransDate<SOPCenaTableView.TransDate) && (SOPCenaTableView.TransDate<='+date2StrXpp(_DATE)+'))');
в запросе превратилось в
((((SOPCenaTable.TransDate<SOPCenaTableView.TransDate) && (SOPCenaTableView.TransDate<=01\09\2016))))
здесь AND написано не так и дата тоже, но условие почему-то сработало
это не случайность? огромное спасибо!
Old 31.01.2017, 11:57   #13  
dech is offline
dech
Участник
dech's Avatar
Самостоятельные клиенты AX
 
650 / 352 (13) ++++++
Join Date: 25.06.2009
Location: Омск
Blog Entries: 3
Quote:
Originally Posted by Яга1 View Post
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
Old 31.01.2017, 12:37   #14  
Яга1 is offline
Яга1
Участник
 
8 / 10 (1) +
Join Date: 30.01.2017
Тогда условия связались по OR:
(((SOPCenaTable.TransDate < SOPCenaTableView.TransDate)) OR (TransDate<={ts '2016-09-01 00:00:00.000'}))
Old 31.01.2017, 23:01   #15  
AlGol is offline
AlGol
Участник
 
277 / 93 (4) ++++
Join Date: 24.12.2001
Location: Тверь.
Quote:
решили хранить не прейкурант полностью, а таблицу, что цена на такой-то ItemId меняется с такой-то даты на такую-то (иногда на 0).
Может проще будет доработать таблицу с ценами до полноценной реализации модели ValidFrom-ValidTo?
Добавить поле даты окончания срока действия цены ValidTo, заполнять его по умолчанию максимальной датой, а при создании строки с последующей датой заполнять его соответстующим значением окончания срока действия.

Тогда запросы по актуальным ценам упростятся до
[дата цены]>=ValidFrom AND [дата цены] <= ValidTo.
__________________
Ален ноби, ностра алис.
Что означает - если один человек построил, другой завсегда разобрать может.
Old 01.02.2017, 09:25   #16  
KiselevSA is offline
KiselevSA
Злыдни
KiselevSA's Avatar
Злыдни
Лучший по профессии 2015
 
958 / 333 (13) ++++++
Join Date: 25.01.2002
Location: Москва
Quote:
Originally Posted by AlGol View Post
Может проще будет доработать таблицу с ценами до полноценной реализации модели ValidFrom-ValidTo?
.
C ценами нельзя использовать такую модель, т.к. полноценная реализация запрещает иметь пересекающиеся диапазоны. В реально жизни очень часто встречаются маркетинговые акции, действующие короткий срок и с ценами ниже обычной. После окончания маркетинговой акции опять создавать нормальные цены? В свою бытность, помню, даже мутили специальную модификацию, которая выполняла последовательное создание ценового соглашения, если в журнале цен у записи была указана дата окончания действия: закрыть предыдущую датой начала и создать копию с датой начала равной дате окончания + 1.
__________________
люди...считают, что если техника не ломается, то ее не нужно ремонтировать. Инженеры считают, что если она не ломается, то нуждается в совершенствовании.
Old 01.02.2017, 09:35   #17  
dn is offline
dn
Участник
Самостоятельные клиенты AX
 
486 / 159 (6) ++++++
Join Date: 26.03.2003
Location: Москва
Quote:
Originally Posted by KiselevSA View Post
C ценами нельзя использовать такую модель, т.к. полноценная реализация запрещает иметь пересекающиеся диапазоны. В реально жизни очень часто встречаются маркетинговые акции, действующие короткий срок и с ценами ниже обычной. После окончания маркетинговой акции опять создавать нормальные цены?
Это решается. У нас, например, сделан отдельный тип ЖКС Акция. При его разноске дополнительно действующая цена закрывается за день до начала акции + создается копия этой цены с датой начала на день позже даты окончания акции.
Old 01.02.2017, 09:43   #18  
AlGol is offline
AlGol
Участник
 
277 / 93 (4) ++++
Join Date: 24.12.2001
Location: Тверь.
Quote:
Originally Posted by KiselevSA View Post
очень часто встречаются маркетинговые акции, действующие короткий срок и с ценами ниже обычной. После окончания маркетинговой акции опять создавать нормальные цены?
В свою бытность, помню, даже мутили специальную модификацию, которая выполняла последовательное создание ценового соглашения, если в журнале цен у записи была указана дата окончания действия: закрыть предыдущую датой начала и создать копию с датой начала равной дате окончания + 1.
Да, подобные алгоритмы и подразумевают нормальную непротиворечивую реализацию модели ValidFrom-ValidTo (или Date Effective Framework как это названо в AX2012).

И создавать нормальную цену на последующий период, по идее, нужно не при прекращении действия краткосрочного ценового соглашения, а в тот момент когда становится известным срок окончания акции. Как правило, это бывает уже в начале действия акции.
__________________
Ален ноби, ностра алис.
Что означает - если один человек построил, другой завсегда разобрать может.
This post has been rated by: dn (1).
Old 01.02.2017, 11:56   #19  
Яга1 is offline
Яга1
Участник
 
8 / 10 (1) +
Join Date: 30.01.2017
Quote:
Originally Posted by AlGol View Post
Может проще будет доработать таблицу с ценами до полноценной реализации модели ValidFrom-ValidTo?
Добавить поле даты окончания срока действия цены ValidTo, заполнять его по умолчанию максимальной датой, а при создании строки с последующей датой заполнять его соответстующим значением окончания срока действия.

Тогда запросы по актуальным ценам упростятся до
[дата цены]>=ValidFrom AND [дата цены] <= ValidTo.
А также нужно возвращать в ValidTо максимальную дату, если новая строка цен удалилась
И не максимальную, а какую-то там еще, если удалилась не последняя строка
И при изменении ValidFrom, если в результате строка перескакивает через несколько строк назад, тоже исправить ValidTo.
Мы уже делали так. Впечатление, что ПРОЩЕ все-таки qbrCena2TransDate.value('((SOPCenaTable.TransDate<SOPCenaTableView.TransDate) && (SOPCenaTableView.TransDate<='+date2StrXpp(_DATE)+'))'); как предложил Wamr
Наглядно и точно нет ошибок при пересчете ValidTo
Old 01.02.2017, 13:06   #20  
Владимир Максимов is offline
Владимир Максимов
Участник
КОРУС Консалтинг
 
1,715 / 1204 (44) ++++++++
Join Date: 13.01.2004
Blog Entries: 3
Quote:
Originally Posted by Яга1 View Post
Впечатление, что ПРОЩЕ все-таки
Есть два связанных между собой процесса
  1. Запись и модификация данных
  2. Выборка данных для анализа
Проблема в том, что структура данных, оптимальная для первого процесса, будет не оптимальная для второго. Ну, и наоборот. Просто "целевая аудитория" у этих процессов разная. Выборка - для человека, а хранение - для "железа"

Вы выбрали структуру данных, оптимальную для первого процесса (запись и модификация данных). Но, как Вы видите в данной теме, эта структура создает проблемы при выборке и анализе данных.

Однако если модифицировать структуру данных для оптимальной выборки и анализа, то она будет не оптимальна для модификации и хранения.

И тут вопрос в том, что для Вас важнее? Что чаще придется делать? Ведь, в конце концов, написать код триггерров на insert/update/delete придется только один раз. Пусть даже он будет достаточно сложным. А вот выборки цен Вы будете делать еще много раз и по разным поводам. И каждый раз Вы будете мучительно долго вспоминать, как же это все "упихать" в один запрос, причем в синтаксисе Axapta.
__________________
- Может, я как-то неправильно живу?!
- Отчего же? Правильно. Только зря...
 

Similar Threads
Thread Thread Starter Forum Replies Last Post
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

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Forum Jump

Рейтинг@Mail.ru
All times are GMT +3. The time now is 10:21.
Powered by vBulletin® Version 3.8.5
Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
Contacts E-mail, Advertising.