Тема: select sum(amount)
Показать сообщение отдельно
Старый 17.11.2006, 12:22   #28  
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)
)