|
|
#21 |
|
Member
|
Цитата:
Сообщение от Gustav
...
select sum(amount) from payTrans where... человек, знакомый с "нормальным" SQL ...
__________________
С уважением, glibs® |
|
|
|
|
#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 является как бы не "самим собой", а содержит всего-навсего количество записей в конкретной таблице. Согласитесь, для "неокрепшего мозга", это немного башне-сносящая откровенность. "Мы понимаем, что мы чего-то не понимаем..."
|
|
|
|
|
#23 |
|
Участник
|
Странно, но имея довольно богатый опыт работы с T-SQL у меня лично не возникло проблем в "догонянии" что делает select count(RecId) from RAssetTable
Не помню, чтобы заморачивался. Просто если вы в T-SQL пишете PHP код:
Вот потому, наверное, и сделано так - чтобы не делать "виртуальных" динамически создающихся dataset'ов... Хотя, конечно, мне, как разработчику, жутко не хватает конструкций типа такой: PHP код:
Но, тем не менее, embedded SQL и табличные переменные X++ RULEZzz!
|
|
|
|
|
#24 |
|
MCTS
|
а если я хочу после этой конструкции обратиться не к полученной переменной, которая содержит подсчитанную сумму, а к полю записи этой таблицы (т.е. к обычному текущему курсору), тогда интересно что делать? Ведь если я пишу
RPayTrans.Amount, то это выдаст ту самую сумму по записям, с другой стороны, мне нужно обратиться к конкретной записи по полю, т.е. RPayTrans.Amount - как тогда быть? |
|
|
|
|
#25 |
|
Злыдни
|
Сделать выборку записи, т.е. select без агрегирования
|
|
|
|
| За это сообщение автора поблагодарили: Eldar9x (1). | |
|
|
#26 |
|
Программатор
|
|
|
|
|
| За это сообщение автора поблагодарили: Eldar9x (1). | |
|
|
#27 |
|
Moderator
|
Eldar9x, рекомендую еще обратить внимание на мою тему Прикольная конструкция: оператор select с полем (она также внизу болтается в "Похожих темах" к этой теме). Думаю, Вам понравится.
|
|
|
|
|
#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) ) |
|
|
|
|
#29 |
|
Участник
|
Добрый вечер!
У меня есть название поля в таблице считай "amount", т.е : fieldId = fieldName2Id(tableNum(RPayTrans), "amount"); RPayTrans.(fieldId); Как мне к нему обратится, в конструкции "Select sum() from"? |
|
|
|
|
#30 |
|
Участник
|
Можно так:
X++: Query q = new Query(''); QueryBuildDatSource ds; ; ds = q.addDataSource(TableNum(RPayTrans)); ds.addSelectiontField(fieldName2Id(tableNum(RPayTrans), "amount"), SelectionField::Sum); |
|
|
|
|
#31 |
|
Участник
|
|
|
|
|
|
#32 |
|
Участник
|
Трудно сказать. Правильнее наверное было бы не передавать. То ли в предыдущих версиях аксапты этот параметр был обязательным, то ли у предыдущего программиста были свои сообращения на этот счет. Но факт остается фактом - данная конструкция благодаря буферу обмена расплодилась по всему коду приложения.
|
|
|
|
|
#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
__________________
Ибо зло есть лучшая сила человека. "Человек должен становиться все лучше и злее" -- так учу я. /Ф. Ницше/ |
|
|
|
|
#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. |
|
|