|  16.11.2006, 18:48 | #21 | 
| Member | Цитата: 
		
			Сообщение от Gustav
			
			 ... select sum(amount) from payTrans where... человек, знакомый с "нормальным" SQL ... 
				__________________ С уважением, glibs® | 
|  | 
|  16.11.2006, 19:47 | #22 | 
| Moderator | Цитата: Вот, не мудрствуя, скопировал из хелпа по 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 | #23 | 
| Участник | 
			
			Странно, но имея довольно богатый опыт работы с T-SQL у меня лично не возникло проблем в "догонянии" что делает select count(RecId) from RAssetTable Не помню, чтобы заморачивался. Просто если вы в T-SQL пишете PHP код: 
			Вот потому, наверное, и сделано так - чтобы не делать "виртуальных" динамически создающихся dataset'ов... Хотя, конечно, мне, как разработчику, жутко не хватает конструкций типа такой: PHP код: 
			Но, тем не менее, embedded SQL и табличные переменные X++ RULEZzz!   | 
|  | 
|  17.11.2006, 10:13 | #24 | 
| MCTS | 
			
			а если я хочу после этой конструкции обратиться не к полученной переменной, которая содержит подсчитанную сумму, а к полю записи этой таблицы (т.е. к обычному текущему курсору), тогда интересно что делать? Ведь если я пишу  RPayTrans.Amount, то это выдаст ту самую сумму по записям, с другой стороны, мне нужно обратиться к конкретной записи по полю, т.е. RPayTrans.Amount - как тогда быть? | 
|  | 
|  17.11.2006, 10:21 | #25 | 
| Злыдни | 
			
			Сделать выборку записи, т.е. select без агрегирования    | 
|  | |
| За это сообщение автора поблагодарили: Eldar9x (1). | |
|  17.11.2006, 10:22 | #26 | 
| Программатор | |
|  | |
| За это сообщение автора поблагодарили: Eldar9x (1). | |
|  17.11.2006, 10:28 | #27 | 
| Moderator | 
			
			Eldar9x, рекомендую еще обратить внимание на мою тему Прикольная конструкция: оператор select с полем (она также внизу болтается в "Похожих темах" к этой теме). Думаю, Вам понравится.    | 
|  | 
|  17.11.2006, 12:22 | #28 | 
| Moderator | небольшой офф-топик про WITH Цитата:   Хлебнув чуть больше года назад в 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Код: 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) ) | 
|  | 
|  31.01.2007, 19:07 | #29 | 
| Участник | 
			
			Добрый вечер! У меня есть название поля в таблице считай "amount", т.е : fieldId = fieldName2Id(tableNum(RPayTrans), "amount"); RPayTrans.(fieldId); Как мне к нему обратится, в конструкции "Select sum() from"? | 
|  | 
|  01.02.2007, 14:03 | #30 | 
| Участник | 
			
			Можно так: X++: Query q = new Query(''); QueryBuildDatSource ds; ; ds = q.addDataSource(TableNum(RPayTrans)); ds.addSelectiontField(fieldName2Id(tableNum(RPayTrans), "amount"), SelectionField::Sum); | 
|  | 
|  01.02.2007, 15:41 | #31 | 
| Участник | |
|  | 
|  01.02.2007, 16:10 | #32 | 
| Участник | 
			
			Трудно сказать. Правильнее наверное было бы не передавать. То ли в предыдущих версиях аксапты этот параметр был обязательным, то ли у предыдущего программиста были свои сообращения на этот счет. Но факт остается фактом - данная конструкция благодаря буферу обмена расплодилась по всему коду приложения.
		 | 
|  | 
|  01.02.2007, 16:20 | #33 | 
| злыдень | 
			
			УжОс! Многа букв. И слава богу что нет.. Я одного не понимаю чем этот изврат, которого нет, лучше хранимок и триггеров которые везде есть уже 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
				__________________ Ибо зло есть лучшая сила человека. "Человек должен становиться все лучше и злее" -- так учу я. /Ф. Ницше/ | 
|  | 
|  01.02.2007, 16:41 | #34 | 
| Участник | 
			
			А еще CTE (они, кстати, появились в MS SQL 2005) можно определять рекурсивно: Код: WITH DirectReports(ManagerID, EmployeeID, EmployeeLevel) AS 
(
    SELECT ManagerID, EmployeeID, 0 AS EmployeeLevel
    FROM HumanResources.Employee
    WHERE ManagerID IS NULL
    UNION ALL
    SELECT e.ManagerID, e.EmployeeID, EmployeeLevel + 1
    FROM HumanResources.Employee e
        INNER JOIN DirectReports d
        ON e.ManagerID = d.EmployeeID 
)
SELECT ManagerID, EmployeeID, EmployeeLevel 
FROM DirectReports ;Последний раз редактировалось belugin; 01.02.2007 в 16:43. | 
|  |