11.11.2011, 09:11 | #1 |
Участник
|
Правильный поиск в истории цен
Доброе утро!
Возникла такая проблема. Есть таблица История цен (RetailItemPriceHistory), в которой записывается розничная цена при каждом ее изменении. То есть история ведется не на каждый день, а только на те дни, когда произошло изменение цены. И вот возникает проблема поиска вот этой цены по определенной выборке. Пример: допустим надо найти минимальную цену за период с 05.01.2011 по 20.02.2011 по конкретному товару. В таблице есть только 3 строки с разными датами по этому артикулу (есть еще склад, но его опустим): itemid transdate price 000001 01.01.2011 100 000001 07.01.2011 110 000001 15.02.2011 105 Делаем выборку таким образом: X++: select minOf(NewPrice) from RetailItemPriceHistory where RetailItemPriceHistory.ItemId == itemId && RetailItemPriceHistory.InventLocationId == InventLocationId && RetailItemPriceHistory.TransDate >= "05.01.2011" && RetailItemPriceHistory.TransDate <= "20.02.2011" && RetailItemPriceHistory.NewPrice; А правильная цена за этот период является 100, т.к. период указан начиная с 05.01.2011 и цена действовала в тот момент получается с 01.01.2011 по 07.01.2011 равной 100. Подскажите как учесть эту цену? У меня возникли 2 идеи по поводу решения этой задачи: 1. Написать метод, кот. будет возвращать мин. цену следующим образом: Первый запрос будет таким, который представлен выше (Находим 1-ю мин.цену). Второй запрос: X++: select firstonly RetailItemPriceHistory order by RecId where RetailItemPriceHistory.ItemId == itemId && RetailItemPriceHistory.InventLocationId == InventLocationId && RetailItemPriceHistory.TransDate >= "05.01.2011" && RetailItemPriceHistory.TransDate <= "20.02.2011" && RetailItemPriceHistory.NewPrice; itemid transdate price 000001 07.01.2011 110 Третий запрос: Находим 2-ю минимальную цену след.образом: X++: select firstonly RetailItemPriceHistory2 order by RecId where RetailItemPriceHistory2.ItemId == RetailItemPriceHistory itemId && RetailItemPriceHistory2.InventLocationId == RetailItemPriceHistory.InventLocationId && RetailItemPriceHistory2.RecId < RetailItemPriceHistory.RecId && RetailItemPriceHistory2.NewPrice; Выглядит уже очень коряво, посему и пишу вам =) (Знаю что с датами запросы не отработают, поставил для наглядности) 2-й способ: Прикрутить таблицу с датами к истории и после найти мин.цену (В SQL вижу как сделать, а в аскапте пока думаю..) Спасибо! |
|
11.11.2011, 09:21 | #2 |
Участник
|
может лучше найти цену на начало периода и сравнить с ценой из первого запроса?
|
|
|
За это сообщение автора поблагодарили: S.Kuskov (1). |
11.11.2011, 09:27 | #3 |
Участник
|
Я бы второй запрос переписал вот так
X++: select firstonly RetailItemPriceHistory2 order by TransDate desc where RetailItemPriceHistory2.ItemId == itemId && RetailItemPriceHistory2.InventLocationId == InventLocationId && RetailItemPriceHistory2.TransDate < "05.01.2011" && RetailItemPriceHistory2.NewPrice; |
|
|
За это сообщение автора поблагодарили: Borsugg (1). |
11.11.2011, 09:27 | #4 |
Участник
|
Цитата:
Я вот это и пытаюсь сделать =)) Только как указать правильно условие, чтобы он подхватил вот эту строку: itemid transdate price 000001 01.01.2011 100 Найти получается как-то таким образом: X++: select firstonly RetailItemPriceHistory order by TransDate desc where RetailItemPriceHistory.ItemId == itemId && RetailItemPriceHistory.InventLocationId == InventLocationId && RetailItemPriceHistory.TransDate <= "05.01.2011" && RetailItemPriceHistory.NewPrice; Последний раз редактировалось Borsugg; 11.11.2011 в 09:35. |
|
11.11.2011, 09:35 | #5 |
Участник
|
Цитата:
Сообщение от S.Kuskov
Я бы второй запрос переписал вот так
X++: select firstonly RetailItemPriceHistory2 order by TransDate desc where RetailItemPriceHistory2.ItemId == itemId && RetailItemPriceHistory2.InventLocationId == InventLocationId && RetailItemPriceHistory2.TransDate < "05.01.2011" && RetailItemPriceHistory2.NewPrice; |
|
11.11.2011, 09:38 | #6 |
Наблюдатель
|
Цитата:
select firstonly price from... order by transdate desc where transdate <= startperiod
__________________
Ax 3.0 SP3 |
|
11.11.2011, 09:48 | #7 |
Участник
|
|
|
11.11.2011, 09:58 | #8 |
Ищущий знания...
|
можно сделать одним запросом
X++: select firstonly NewPrice from RetailItemPriceHistory order by NewPrice where RetailItemPriceHistory.ItemId == itemId && RetailItemPriceHistory.InventLocationId == InventLocationId && RetailItemPriceHistory.TransDate >= "05.01.2011" && RetailItemPriceHistory.TransDate <= "20.02.2011" && RetailItemPriceHistory.NewPrice join firstonly NewPrice from RetailItemPriceHistory2 order by TransDate desc where RetailItemPriceHistory2.ItemId == RetailItemPriceHistory.ItemId && RetailItemPriceHistory2.InventLocationId == RetailItemPriceHistory.InventLocationId && RetailItemPriceHistory2.TransDate < "05.01.2011"; return min(RetailItemPriceHistory.NewPrice, RetailItemPriceHistory2.NewPrice);
__________________
"Страх перед возможностью ошибки не должен отвращать нас от поисков истины." (с) С Уважением, Елизаров Артем |
|
11.11.2011, 09:59 | #9 |
Участник
|
|
|
11.11.2011, 10:03 | #10 |
Ищущий знания...
|
Там же сделана сортировка по цене по умолчанию она "ASC" - от сюда следут, что будет возвращена минимальная цена в периоде (если это не так и тест это подтверждает, напишите плиз)
__________________
"Страх перед возможностью ошибки не должен отвращать нас от поисков истины." (с) С Уважением, Елизаров Артем |
|
11.11.2011, 10:07 | #11 |
Участник
|
Теоретически может так оказаться, что одна из частей запроса не найдёт не одной записи (например период в которм ищем минимальную цену начинается раньше чем первая запись о цене). И тогда джойн не вернёт ничего.
В случае с двумя запросами, перед тем как искать минимум среди двух результатов нужно принудительно проверить что результаты не пусты. Последний раз редактировалось S.Kuskov; 11.11.2011 в 10:14. |
|
11.11.2011, 10:16 | #12 |
Ищущий знания...
|
Цитата:
X++: .... Price returnPrice; ; select firstonly NewPrice from RetailItemPriceHistory order by NewPrice where RetailItemPriceHistory.ItemId == itemId && RetailItemPriceHistory.InventLocationId == InventLocationId && RetailItemPriceHistory.TransDate >= "05.01.2011" && RetailItemPriceHistory.TransDate <= "20.02.2011" && RetailItemPriceHistory.NewPrice join firstonly NewPrice from RetailItemPriceHistory2 order by TransDate desc where RetailItemPriceHistory2.ItemId == RetailItemPriceHistory.ItemId && RetailItemPriceHistory2.InventLocationId == RetailItemPriceHistory.InventLocationId && RetailItemPriceHistory2.TransDate < "05.01.2011"; if (RetailItemPriceHistory.RecId != 0) returnPrice = min(RetailItemPriceHistory.NewPrice, RetailItemPriceHistory2.NewPrice); else { select minOf(NewPrice) from RetailItemPriceHistory where RetailItemPriceHistory.ItemId == itemId && RetailItemPriceHistory.InventLocationId == InventLocationId && RetailItemPriceHistory.TransDate >= "05.01.2011" && RetailItemPriceHistory.TransDate <= "20.02.2011" && RetailItemPriceHistory.NewPrice; returnPrice = RetailItemPriceHistory.NewPrice; } return returnPrice;
__________________
"Страх перед возможностью ошибки не должен отвращать нас от поисков истины." (с) С Уважением, Елизаров Артем |
|
|
За это сообщение автора поблагодарили: Borsugg (1). |
11.11.2011, 10:26 | #13 |
Участник
|
Цитата:
Сообщение от lev
да, такое возможно... я думаю что можно это будет учесть. в начале выбрать с помощью джойна, если там ничего не нашлось, тогда получается что достаточно сделать один запрос с указанием периода. он и найдет минимальную цену. Т.е. в итоге метод получится что то типа:
X++: .... .... if (RetailItemPriceHistory.RecId != 0) returnPrice = min(RetailItemPriceHistory.NewPrice, RetailItemPriceHistory2.NewPrice); else { select minOf(NewPrice) from RetailItemPriceHistory where RetailItemPriceHistory.ItemId == itemId && RetailItemPriceHistory.InventLocationId == InventLocationId && RetailItemPriceHistory.TransDate >= "05.01.2011" && RetailItemPriceHistory.TransDate <= "20.02.2011" && RetailItemPriceHistory.NewPrice; returnPrice = RetailItemPriceHistory.NewPrice; } return returnPrice; Последний раз редактировалось Borsugg; 11.11.2011 в 10:29. |
|
11.11.2011, 10:29 | #14 |
Участник
|
пустой может оказаться и первая часть запроса (например когда цена уже год не менялась, а мы ищем минимум за последний месяц)
|
|
11.11.2011, 10:32 | #15 |
Участник
|
может лучше в качестве оптимизации сделать нужные индексы, чем делать громоздкий код?
|
|
11.11.2011, 10:46 | #16 |
Ищущий знания...
|
Цитата:
Цитата:
Сообщение от Borsugg
А если RetailItemPriceHistory.RecId и так ничего не вернул в первом запросе с join'ом, то скорее же всего и второй запрос тоже ничего не вернет? Условия выборки то одинаковые...
второй запрос вернет если в заданном периоде есть записи. это разные выборки.
__________________
"Страх перед возможностью ошибки не должен отвращать нас от поисков истины." (с) С Уважением, Елизаров Артем |
|
11.11.2011, 10:46 | #17 |
Участник
|
|
|
11.11.2011, 10:48 | #18 |
Участник
|
|
|
11.11.2011, 10:55 | #19 |
Участник
|
|
|
|
За это сообщение автора поблагодарили: Borsugg (1). |
11.11.2011, 11:50 | #20 |
Участник
|
Цитата:
X++: FromDate fromDate = 05\01\2011; ToDate toDate = 20\02\2011; newPrice minNewPrice = maxInt(); ; while select NewPrice, TransDate from RetailItemPriceHistory order by TransDate desc where RetailItemPriceHistory.ItemId == itemId && RetailItemPriceHistory.InventLocationId == InventLocationId && RetailItemPriceHistory.TransDate <= toDate && RetailItemPriceHistory.NewPrice { minNewPrice = min(minNewPrice, RetailItemPriceHistory.NewPrice); // Сравнение с начальной датой ПОСЛЕ вычисления значения // чтобы учесть цену, указанную ДО начальной даты if (RetailItemPriceHistory.TransDate <= fromDate) { break; } } if (minNewPrice == maxInt()) { // На дату окончания периода нет цены minNewPrice = 0; } X++: FromDate fromDate = 05\01\2011; ToDate toDate = 20\02\2011; ; // Уточняем "начальную дату" select firstonly TransDate from RetailItemPriceHistory order by TransDate desc where RetailItemPriceHistory.ItemId == itemId && RetailItemPriceHistory.InventLocationId == InventLocationId && RetailItemPriceHistory.TransDate <= fromDate && RetailItemPriceHistory.NewPrice; // Если есть запись с датой меньше начальной и нет записи с датой // равной начальной, то начальной датой считаем найденное значение if (RetailItemPriceHistory.TransDate < fromDate) { fromDate = RetailItemPriceHistory.TransDate; } // Теперь собственно запрос select minOf(NewPrice) from RetailItemPriceHistory where RetailItemPriceHistory.ItemId == itemId && RetailItemPriceHistory.InventLocationId == InventLocationId && RetailItemPriceHistory.TransDate >= fromDate && RetailItemPriceHistory.TransDate <= toDate && RetailItemPriceHistory.NewPrice;
__________________
- Может, я как-то неправильно живу?! - Отчего же? Правильно. Только зря... |
|
|
За это сообщение автора поблагодарили: Borsugg (1). |
Теги |
retailitempricehistory, запрос (query) |
|
Похожие темы | ||||
Тема | Ответов | |||
Поиск набором в выпадающем списке.. | 0 | |||
Поиск сотрудников по наименованию (ФИО) в AX 2009 | 12 | |||
"поиск" | 6 | |||
Поиск по подстроке | 8 | |||
Поиск по полю временной таблицы | 2 |
|