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

 
 
Опции темы Поиск в этой теме Опции просмотра
Старый 16.11.2006, 16:19   #1  
Eldar9x is offline
Eldar9x
MCTS
Аватар для Eldar9x
Oracle
MCBMSS
 
1,064 / 166 (8) ++++++
Регистрация: 29.09.2006
Адрес: Казань
Цитата:
Сообщение от Sada Посмотреть сообщение
это сумма по нескольким записям
странно, а я думал, что это обращение к полю данной таблицы???
Старый 16.11.2006, 16:46   #2  
Gustav is offline
Gustav
Moderator
Аватар для Gustav
SAP
Лучший по профессии 2009
 
1,858 / 1152 (42) ++++++++
Регистрация: 24.01.2006
Адрес: Санкт-Петербург
Записей в блоге: 19
Цитата:
Сообщение от Eldar9x Посмотреть сообщение
странно, а я думал, что это обращение к полю данной таблицы???
Eldar9x, мне примерно понятно ваше недоумение. Я сам через это проходил.
Недоумение возникает из-за того, что глядя на конструкцию:

select sum(amount) from payTrans where...

человек, знакомый с "нормальным" SQL (и пока не очень знакомый с "аксаптовским"), понимает, что "нормальный" SQL предъявит в качестве результата такого запроса "сумму поля amount из таблицы payTrans по тем записям, которые отбираются условием where...". Причем в контексте конкретной процедуры (метода) возникает естественный вопрос: "А где же оператор присваивания? Чему это полученное значение присваивается?"

На "аксаптовском SQL", а точнее на X++, вышеупомянутая конструкция означает, что "результат запроса на нормальном SQL" будет помещен в поле amount табличной переменной payTrans.
Т.е. на некотором псевдокоде можно записать примерно так:

payTrans.amount = (select sum(amount) from RPayTrans where ... )

Это просто нужно немножко переварить и прочувствовать (рюмка хорошего коньяка будет нелишней!).
За это сообщение автора поблагодарили: Eldar9x (1).
Старый 16.11.2006, 16:54   #3  
Eldar9x is offline
Eldar9x
MCTS
Аватар для Eldar9x
Oracle
MCBMSS
 
1,064 / 166 (8) ++++++
Регистрация: 29.09.2006
Адрес: Казань
Вот вот, мне тоже вначале хотелось увидеть что нибудь типа
blablabla = (select sum(amount) from RPayTrans where ... ),
где blablabla, какая то переменная...
Старый 16.11.2006, 18:48   #4  
glibs is offline
glibs
Member
Сотрудники компании It Box
Most Valuable Professional
Лучший по профессии 2011
Лучший по профессии 2009
 
4,942 / 911 (40) +++++++
Регистрация: 10.06.2002
Адрес: I am from Kyiv, Ukraine. Now I am in Moscow. For private contacts: glibs@hotmail.com
Цитата:
Сообщение от Gustav
...
select sum(amount) from payTrans where...

человек, знакомый с "нормальным" SQL
...
Хм... по-моему, в T-SQL при работе с курсором конструкция примерно такая же. Вы объявляете некий запрос в качестве курсора (он может содержать и агрегатные функции), а потом перебираете его строки. При этом вы тоже не работаете с конкретной записью.
__________________
С уважением,
glibs®
Старый 16.11.2006, 19:47   #5  
Gustav is offline
Gustav
Moderator
Аватар для Gustav
SAP
Лучший по профессии 2009
 
1,858 / 1152 (42) ++++++++
Регистрация: 24.01.2006
Адрес: Санкт-Петербург
Записей в блоге: 19
Цитата:
Сообщение от glibs Посмотреть сообщение
Хм... по-моему, в T-SQL при работе с курсором конструкция примерно такая же. Вы объявляете некий запрос в качестве курсора (он может содержать и агрегатные функции), а потом перебираете его строки. При этом вы тоже не работаете с конкретной записью.
Нуу, речь, скорее, идет не о том, что "не с конкретной записью", а о сомнительной наглядности синтаксисе конструкции... Авторы самого X++ уж больно всё лаконично попытались описать. И эта лаконичность, увы, часто не льет воду не мельницу понимания, а скорее наоборот выходит некоторым боком (во завернул!)

Вот, не мудрствуя, скопировал из хелпа по T-SQL кусочек примера с курсором:
Код:
DECLARE @au_id varchar(11), @au_fname varchar(20), @au_lname varchar(40)
 
DECLARE authors_cursor CURSOR FOR 
SELECT au_id, au_fname, au_lname
FROM authors
WHERE state = "UT"
ORDER BY au_id
 
OPEN authors_cursor
 
FETCH NEXT FROM authors_cursor 
INTO @au_id, @au_fname, @au_lname
если читать это как бы на естественном языке, то получается примерно следующее:
Код:
ОБЪЯВЛЯЕМ наши_переменные
 
ОБЪЯВЛЯЕМ наш_курсор КАК КУРСОР ДЛЯ
SELECT... (причем SELECT - на нормальном SQL!)
 
ОТКРЫВАЕМ наш_курсор
 
СЧИТЫВАЕМ ОЧЕРЕДНУЮ (запись) ИЗ наш_курсор
В наши_переменные
Акцентирую внимание на последнем: СЧИТЫВАЕМ запись ИЗ наш_курсор В наши_переменные. ИЗ - В, ИЗ - В.

А здесь что? select sum(amount) from payTrans - ВЫБИРАЕМ СУММУ(amount) ИЗ... ВЫБИРАЕМ - ИЗ, ВЫБИРАЕМ - ИЗ. Ну, ИЗ-то выбираем, а ВО ЧТО выбираем-то? Вот и возникают непонятки. По-моему, вполне обоснованные.

У меня знакомство с подобного рода "проблемой" началось со встречи с примерно таким фрагментом:

select count(RecId) from RAssetTable

Уже к тому времени зная ответственно-почётную миссию идентификатора RecId во всей системе, мозг упорно отказывался понимать, что в этом фрагменте RecId является как бы не "самим собой", а содержит всего-навсего количество записей в конкретной таблице. Согласитесь, для "неокрепшего мозга", это немного башне-сносящая откровенность. "Мы понимаем, что мы чего-то не понимаем..."
Старый 17.11.2006, 09:49   #6  
Deep Dreamer is offline
Deep Dreamer
Участник
 
76 / 25 (1) +++
Регистрация: 05.03.2004
Адрес: Москва
Странно, но имея довольно богатый опыт работы с T-SQL у меня лично не возникло проблем в "догонянии" что делает select count(RecId) from RAssetTable
Не помню, чтобы заморачивался.
Просто если вы в T-SQL пишете
PHP код:
select count(recidfrom bmssa.LEDGERJOURNALTRANS 
то получите некий набор данных. Поскольку dataset будет содержать заказаный набор данных - т.е. что написано между select и from то и получите, особенно если переименоввывать колонки. Это очень гибко с одной стороны, но это слабо формализуемо с точки зрения embedded SQL языка X++...
Вот потому, наверное, и сделано так - чтобы не делать "виртуальных" динамически создающихся dataset'ов...
Хотя, конечно, мне, как разработчику, жутко не хватает конструкций типа такой:
PHP код:
select JOURNALNAMEAPPROVEDBY from dbo.LEDGERJOURNALTABLE as LJT
join 
(select JOURNALNUMcount(recid) as cnt from dbo.LEDGERJOURNALTRANS group by JOURNALNUM) as tmp
on tmp
.cnt and LJT.JOURNALNUM tmp.JOURNALNUM 
Имеется в виду нехватает вложенных select'ов, особенно с аггрегатными поименованными полями
Но, тем не менее, embedded SQL и табличные переменные X++ RULEZzz!
Старый 17.11.2006, 12:22   #7  
Gustav is offline
Gustav
Moderator
Аватар для Gustav
SAP
Лучший по профессии 2009
 
1,858 / 1152 (42) ++++++++
Регистрация: 24.01.2006
Адрес: Санкт-Петербург
Записей в блоге: 19
небольшой офф-топик про WITH
Цитата:
Сообщение от Deep Dreamer Посмотреть сообщение
Имеется в виду нехватает вложенных select'ов, особенно с аггрегатными поименованными полями
Не хватает явно! Увы, много чего не хватает...

Хлебнув чуть больше года назад в Oracle 9.2 SQL-счастье под названием "фраза WITH с подзапросом" (subquery factoring clause), я уже с трудом понимаю, как можно возвращаться в такой каменный век SQL, где этого нет. Чесслово, говорю это не пижонства или красного словца ради. Несмотря на то, что синтаксис ANSI-шный, Microsoft, к сожалению, вроде не торопится прикручивать эту фичу к SQL Server (или может сделали уже?!) А вот обладатели Oracle 9.2 и выше, кто еще не в курсе, рекомендую обратить на этот WITH пристальное внимание.

В качестве примера привожу один свой рабочий запрос. Этот запрос выбирает неамортизируемые карточки основных средств в некоторой модели учета ОС ('GAAP') на определенную дату. Вникать в его бизнес-суть абсолютно необязательно. Это просто иллюстрация того, как подзапросы могут взаимодействовать между собой и как можно эффективно структурировать сложные запросы (практически в этаком "последовательно-процедурном" стиле, невиданном доселе для SELECT'ов):
Код:
SELECT * FROM
(
WITH    -- ЗДЕСЬ Я ОПРЕДЕЛЯЮ НЕСКОЛЬКО ИМЕНОВАННЫХ ПОДЗАПРОСОВ (имена "подчеркнуты")
 ------------------ 
 RATrans AS
 ------------------ 
  (SELECT 
   accountnum,
   MIN(CASE WHEN assettranstype = 3 THEN transdate END) acq_transdate,
   SUM(CASE WHEN assettranstype = 0 THEN amountmst ELSE 0 END) amt_0,
   SUM(CASE WHEN assettranstype = 2 THEN amountmst ELSE 0 END) amt_2,
   SUM(CASE WHEN assettranstype = 3 THEN amountmst ELSE 0 END) amt_3,
   SUM(CASE WHEN assettranstype = 4 THEN amountmst ELSE 0 END) amt_4,
   SUM(CASE WHEN assettranstype = 5 THEN amountmst ELSE 0 END) amt_5,
   SUM(CASE WHEN assettranstype = 7 THEN amountmst ELSE 0 END) amt_7,
   SUM(CASE WHEN assettranstype = 15 THEN amountmst ELSE 0 END) amt_15,
   SUM(CASE WHEN assettranstype = 16 THEN amountmst ELSE 0 END) amt_16,
   SUM(CASE WHEN assettranstype NOT IN (0,2,3,4,5,7,15,16) THEN amountmst ELSE 0 END) amt_other
  FROM RASSETTRANS 
  WHERE assetstandardid = 'GAAP'
   AND transdate  <= TO_DATE('30.09.2006', 'DD.MM.YYYY') 
  GROUP BY accountnum
  ),
 ------------------------
 HavingAmort AS
 ------------------------
  (SELECT accountnum 
  FROM RASSETTRANS 
  WHERE assettranstype = 0 
   AND assetstandardid = 'GAAP' 
   AND transdate <= TO_DATE('30.09.2006', 'DD.MM.YYYY')
  ),
 ----------------------------
 NoHavingAmort AS
 ----------------------------
  (SELECT ratable.accountnum AS accountnum
  FROM 
  RASSETTABLE ratable,
  HavingAmort ratrans -- <-- ИСПОЛЬЗУЕМ РАНЕЕ (выше) ОПРЕДЕЛЕННЫЙ ПОДЗАПРОС HavingAmort "как простую таблицу" - неплохо, правда? :-)
  WHERE ratable.accountnum = ratrans.accountnum(+)
   AND ratrans.accountnum IS NULL
  ),
 -------------------------------
 NecessaryAssets AS
 -------------------------------
  -- карточки, не имеющие амортизации в западном учете  (когда либо до даты)
  (SELECT accountnum FROM NoHavingAmort -- -- ОПЯТЬ ИСПОЛЬЗУЕМ РАНЕЕ (выше) ОПРЕДЕЛЕННЫЙ ПОДЗАПРОС NoHavingAmort "как простую таблицу", который в свою очередь - см. выше тоже включает подзапрос HavingAmort, т.е. уже пошла вложенность, сносящая башню при неиспользовании фразы WITH :-)
  UNION
  -- карточки, у которых нет амортизации (отключена)
  SELECT assetid FROM RASSETSTANDARDS WHERE depreciation = 0 AND assetstandardid = 'GAAP'
  UNION
  -- карточки, имеющие ост. стоимость <= 0, но не выбывшие ----------------------------------------------
  SELECT accountnum FROM
  (
   SELECT
   accountnum,
   (amt_2 + amt_3 + amt_4 + amt_16) AS PS,
   -(amt_0) AS Amort
   FROM RATrans  
   WHERE ROUND(amt_5,2) = 0 AND ROUND(amt_7,2) = 0
  ) 
  WHERE ROUND(PS,2) <= ROUND(Amort,2)
  )
--
-- СОБСТВЕННО НАЧИНАЕТСЯ ОСНОВНОЙ СЕЛЕКТ (самый внешний "SELECT * FROM ( WITH ...)" основным не считаем - это обертка для TOAD )
SELECT
 ratable.accountnum AS "Asset Code",
 ratable.dataareaid AS "Company",
 ratable.status AS "Status Value", 
 en.en_label AS "Status Label", 
 stand.depreciation AS "Depr Turn ON",
 neverb4.never_b4 AS "Never Before",
-- 
 CASE WHEN ratable.status <> 7 
  THEN NVL((trans.amt_2 + trans.amt_3 + trans.amt_4 + trans.amt_16), 0) 
  ELSE NVL((trans.amt_2 + trans.amt_3 + trans.amt_4 + trans.amt_16), 0) + NVL(stand.acquisitionprice, 0) 
  END AS "IC",
--
 -NVL(trans.amt_0, 0) AS "Depr",
--
 CASE WHEN ratable.status <> 7 
  THEN NVL((trans.amt_2 + trans.amt_3 + trans.amt_4 + trans.amt_16)+ (trans.amt_0), 0) 
  ELSE NVL((trans.amt_2 + trans.amt_3 + trans.amt_4 + trans.amt_16)+ (trans.amt_0), 0) + NVL(stand.acquisitionprice, 0) 
  END AS "Net",
--
 trans. acq_transdate AS "Acq.Date (GAAP, RATrans)",
 ratable.acquisitiondate AS "Acq.Date (RATable)",
 ratable.acquisitionprice AS "Acq.Price (RATable)",
 stand.acquisitionprice AS "Acq.Price (RAStand)",
 trans.amt_0 AS "Amt_0_Depreciation", 
 trans.amt_2 AS "Amt_2_Revaluation", 
 trans.amt_3 AS "Amt_3_Acquisition", 
 trans.amt_4 AS "Amt_4_AcquisitionAdj", 
 trans.amt_5 AS "Amt_5_DisposalSale", 
 trans.amt_7 AS "Amt_7_Disposal", 
 trans.amt_15 AS "Amt_15_Investment", 
 trans.amt_16 AS "Amt_16_InvestmentOpen", 
 amt_other AS "Amt_Other_AssetTransTypes"
-- 
FROM
-- 
 RATrans trans, -- <-- ИСПОЛЬЗУЕМ ИМЕННОВАННЫЙ ПОДЗАПРОС из зоны WITH
-- 
 (SELECT assetid, acquisitionprice, depreciation 
 FROM RASSETSTANDARDS 
 WHERE assetstandardid = 'GAAP'
 ) stand,
-- 
 -- ДЛЯ ИНДИКАЦИИ: карточки, не имеющие амортизации в западном учете  (когда либо до даты)
 (SELECT accountnum, 'Never' AS never_b4 
 FROM NoHavingAmort -- <-- ИСПОЛЬЗУЕМ ИМЕННОВАННЫЙ ПОДЗАПРОС из зоны WITH
 ) neverb4, 
-- 
 -- расшифровка значений статуса 
 (SELECT * FROM AX_BASE_ENUMS WHERE en_type = 'RAssetStatus') en, 
-- 
 (SELECT accountnum, dataareaid, status, acquisitiondate, acquisitionprice 
 FROM RASSETTABLE 
 ) ratable,
-- 
 NecessaryAssets nassets -- <-- ИСПОЛЬЗУЕМ ИМЕННОВАННЫЙ ПОДЗАПРОС из зоны WITH
-- 
WHERE nassets.accountnum = ratable.accountnum -- здесь без (+) !!!
 AND ratable.status = en.en_value(+)
 AND ratable.accountnum = neverb4.accountnum(+)
 AND ratable.accountnum = stand.assetid(+)  
 AND ratable.accountnum = trans.accountnum(+)
)
ORDER BY 1
Запрос можно попробовать запустить в вашей системе, заменив модель учета 'GAAP' на какую-нибудь модель учета ОС из вашей системы. Также необходимо закомментировать фрагменты, ссылающиеся на мою специфическую таблицу AX_BASE_ENUMS. Ну, или предварительно создать ее в схеме вашей Аксапты (наполнять данными не обязательно - RassetTable вяжется на нее левым джойном):
Код:
CREATE TABLE AX_BASE_ENUMS
(
  EN_TYPE     VARCHAR2(100 BYTE)                NOT NULL,
  EN_VALUE    NUMBER(10)                        NOT NULL,
  EN_LABEL    VARCHAR2(200 BYTE)                NOT NULL,
  EN_ELEMENT  VARCHAR2(100 BYTE)
)
Старый 01.02.2007, 16:20   #8  
Recoilme is offline
Recoilme
злыдень
Аватар для Recoilme
Злыдни
 
895 / 192 (8) ++++++
Регистрация: 18.06.2003
Цитата:
Сообщение от Gustav Посмотреть сообщение
Не хватает явно! Увы, много чего не хватает...
УжОс! Многа букв.
И слава богу что нет.. Я одного не понимаю чем этот изврат, которого нет, лучше хранимок и триггеров которые везде есть уже n десятков лет ???
Неужели программировать в родном "последовательно-процедурном" стиле не приятнее на порядок???
Вот как выглядит типичная обработка на firebird, по моему все понятно без слов:
Код:
AS
declare variable znak integer;
declare variable sumnds double precision;
BEGIN
  IF (NEW.ID IS NULL) THEN
    NEW.ID = GEN_ID(GEN_Z_PROVODKA_ID,1);
  /* Перед подстановкой в основную считаем параметры осн записи и рассчитаем себестоимость*/

  if (new.id_pribyl<>0) then /* Прибыли */
  begin
        select first 1 data, skladkod, statuskod, celkod from Z_PRIBYL
        where Z_PRIBYL.id = NEW.id_pribyl into new.data, new.skladprihod, new.status, new.typeoper;
        select result from f_valuta_calc(new.summaval,new.data,new.valutakod) into new.summaprihod;
        new.summaoper = new.summaprihod;
  end

  if (new.id_ubytok<>0) then/* Убытки */
  begin
        select first 1 data, skladkod, statuskod, celkod from Z_UBYTOK
        where Z_UBYTOK.id = NEW.id_ubytok into new.data, new.skladrashod, new.status, new.typeoper;
        select result from z_ostatok_stoim(new.status,new.tovarkod,new.skladrashod,new.kolnov * (-1)) into new.summarashod;
        new.summaoper = new.summarashod;
  end

  if (new.id_perem <> 0) then /*Перемещения*/
  begin
    select first 1 dataprih, datarash, skladrashodkod, skladprihodkod, statuskod, celkod from Z_PEREM
    where Z_PEREM.id = new.id_perem into new.data,new.datarashod, new.skladrashod, new.skladprihod, new.status, new.typeoper;
    select result from z_ostatok_stoim(new.status,new.tovarkod,new.skladrashod,new.kolnov * (-1)) into new.summarashod;
    new.summaprihod = (-1)*new.summarashod;
    new.summaoper = new.summarashod;
  end

  if (new.id_zpnakl <> 0) then /* Закупка */
  begin
        select first 1 data, skladkod, statuskod, celkod, postkod, valutakod from zp_nakl
        where zp_nakl.id = NEW.id_zpnakl into new.data, new.skladprihod, new.status, new.typeoper, new.postkod, new.valutakod;
        select result from f_valuta_calc((new.summaval-new.summands),new.data,new.valutakod) into new.summaprihod;
        UPDATE ZP_NAKL SET SUMMA = SUMMA + new.summaprihod WHERE (ID = new.id_zpnakl);
        select result from f_valuta_calc(new.summands,new.data,new.valutakod) into new.summaoper;
        UPDATE ZP_NAKL SET SUMMANDS = SUMMANDS + new.summaoper WHERE (ID = new.id_zpnakl);
        new.summaoper = new.summaprihod;
  end

  if (new.id_prnakl <> 0) then /* Продажа */
  begin
        select first 1 data, skladkod, statuskod, celkod, klientkod, valutakod from pr_nakl
        where pr_nakl.id = NEW.id_prnakl into new.data, new.skladrashod, new.status, new.typeoper, new.klientkod, new.valutakod;
        select result from f_valuta_calc(new.summaval-new.summands,new.data,new.valutakod) into new.summaoper;
        select result from z_ostatok_stoim(new.status,new.tovarkod,new.skladrashod,new.kolnov * (-1)) into new.summarashod;
        select result from f_valuta_calc(new.summands,new.data,new.valutakod) into sumnds;
        UPDATE PR_NAKL SET
            SUMMA = SUMMA + new.summaoper,
            SUMMANDS = SUMMANDS + :sumnds
        WHERE (ID = new.id_prnakl);
  end
  if (new.kolnov = 0) then exit;
  /* Контроль */
  if ((new.tovarkod is null) or (new.skladprihod is null AND new.skladrashod is null))  then
    execute procedure ERROR('Проводки в никуда быть не может');
  /* Собственно тригер */
  /* Приход:"+", Расход:"-" */
  if (new.status > 0) then znak = 1; else znak = (-1); /*Возвраты*/
  if (not (new.skladprihod is null)) then
  begin
    new.kolprihod = new.kolnov;
    execute procedure z_ostatok_calc (new.tovarkod,new.skladprihod,new.kolprihod,new.summaprihod,:znak,new.status);
  end
  if (not (new.skladrashod is null)) then
  begin
    new.kolrashod = new.kolnov*(-1);
    execute procedure z_ostatok_calc (new.tovarkod,new.skladrashod,new.kolrashod,new.summarashod,:znak,new.status);
  end
  /* Обновим статусы*/
  if (new.status = 1) then new.ZAAVKA = new.kolnov;
  else
    if (new.status = 2) then new.ZAKAZ = new.kolnov;
    else
        if (new.status = 3) then new.REZERV = new.kolnov;
        else
            if (new.status = 4) then new.PUT = new.kolnov;
            else
                if (new.status = 5) then new.ZAVER6ENO = new.kolnov;

END
__________________
Ибо зло есть лучшая сила человека. "Человек должен становиться все лучше и злее" -- так учу я. /Ф. Ницше/
Теги
amount, запрос (query), как правильно

 

Похожие темы
Тема Автор Раздел Ответов Посл. сообщение
SUM по Amount в Query. С динамическими фильтрами по Grid Poleax DAX: Программирование 8 25.09.2008 16:04
Разница NotInTTS и Found Logger DAX: База знаний и проекты 6 18.09.2008 12:35
Отчет "Запасы в наличии" evb DAX: Программирование 19 17.01.2008 07:37
Вопрос про Demand Planner slava09 DAX: Функционал 4 25.09.2006 11:43
select sum(amount) from временная таблица ATimTim DAX: Программирование 6 11.06.2004 14:16
Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра
Комбинированный вид Комбинированный вид

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

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

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