Как правильно работать с временными таблицами.
На страницу 1, 2 След.
|
Предыдущая тема :: Следующая тема |
Автор |
Сообщение |
Asdn Участник
Вступление в Клуб: 04.10.2011
|
Пт Окт 14, 2011 08:19  Как правильно работать с временными таблицами. |
|
Полезность: Нет оценки
|
Добрый день!
Недавно стал сопровождать IBSO. В процессе разработки отчета потребовалось первоначально данные выбирать во временную таблицу.
из документации понял, что создать таблицу можно след образом
Код: |
type typeRec is record(
C_CLN_TYPE integer, -- физик/юрик
C_FILIAL [BRANCH],
C_DEPART [DEPART],
C_ORG_TYPE varchar2(10),
C_IsServiced boolean,
C_KIND_CREDIT varchar2(10)б
........
);
type data_list is table of typeRec index by integer;
RepTable data_list;
RepTableIdx integer;
|
хотелось бы теперь с временной таблицей работать с помощью операций SELECT, UPDATE, DELETE, LOCATE. возможно ли такое?
например, что нибудь типа
Код: |
locate tmp in RepTable
where
tmp.C_ORG_TYPE = 'SMALL' and tmp.C_IsServiced = 0;
или
select tb( tb.[Idx] : Idx )
in RepTable all
where
tb.C_CLN_TYPE = 0;
или
update tab(tab.[SUMMA] = p_nSum) in ResTable
where tab.KIND_CREDIT = 'CRED_LINE';
|
пробую так делать. выдает ошибку при компиляции.
конечно можно использовать цикл FOR, перебирать последовательно записи таблицы до искомой. получать индекс этой записи. но может существует более элегантное решение? |
|
 |
A_A_A Профи
Вступление в Клуб: 16.07.2009
|
Пт Окт 14, 2011 09:03   |
|
Полезность: Нет оценки
|
при работе с такими таблицами работать с SELECT, UPDATE .. нет возможности.
Нужно как раз использовать FOR |
|
 |
Asdn Участник
Вступление в Клуб: 04.10.2011
|
Пт Окт 14, 2011 09:29   |
|
Полезность: Нет оценки
|
а есть ли какая нибудь альтернатива этим временным таблицам? или только is table of record?
может есть какой то другой функционал, который позволяет создавать временные таблицы для select.... |
|
 |
svn Профи
Вступление в Клуб: 04.02.2008
|
Пт Окт 14, 2011 09:37   |
|
Полезность: Нет оценки
|
есть временные структуры - но их нужно создавать в словаре
можно курсоры заюзать, представления
вы наверно пытаетесь по аналогии с чистым PL\SQL реализовать
ЦФТ это вам не это ) |
|
 |
vtar Эксперт
Вступление в Клуб: 20.03.2009
|
Пт Окт 14, 2011 09:40   |
|
Полезность: Нет оценки
|
Asdn пишет: | а есть ли какая нибудь альтернатива |
1. table может быть только "приемником" результата SELECT
2. создать справочник и использовать его как временную таблицу с полноценными SELECT и UPDATE |
|
 |
nOnAME Участник со стажем
Вступление в Клуб: 25.01.2011
|
Пт Окт 14, 2011 11:07   |
|
Полезность: Нет оценки
|
создать структруру, во вкладке "Таблица" выставить время жизни - только на время сессии(или как то так). Сгенерить там операции NEW#AUTO, EDIT#AUTO, DELETE#AUTO. И работать с ней как с таблицей. Это если хочется на ЦФТ уровне быть.
Еще можно создать временную таблицу в базе (самой базе oracle стандартными средствами). И в процессе "разработки отчета" (или операции какой-нибудь) сделать PL/SQL вставку, где делать все что угодно с Вашей таблицей на привычном языке. Тоже должно отработать. |
|
 |
prog Эксперт
Вступление в Клуб: 03.03.2008
|
Пт Окт 14, 2011 13:20   |
|
Полезность: Нет оценки
|
Посмотрите операцию [RPT_LIC_REPORT]
там есть Код: | select x(x.name,
x.buy_code,
x.statussubsys,
(case
when length(x.color) > 0 then '1'
else '0'
end
),
x.with_sql,
x.lvl
) in VW_SQL_LIC_REPORT%rowtype() |
в то время как VW_SQL_LIC_REPORT это
Код: | SELECT to_number(a.sort_base) sort_base,
a.NAME NAME,
a.buy_code buy_code,
a.statussubsys statussubsys,
a.color color,
a.with_sql with_sql,
a.lvl lvl
FROM TABLE (z$system_lib_lic_rpt.get_report (null,null)) a |
фот эта функция скидывает данные в представление:
z$system_lib_lic_rpt.get_report
Вроде то что вам нужно. |
|
 |
Asdn Участник
Вступление в Клуб: 04.10.2011
|
Пн Окт 17, 2011 02:56   |
|
Полезность: Нет оценки
|
Спасибо за ответы! |
|
 |
Random Эксперт
Вступление в Клуб: 27.06.2011
|
Пн Окт 17, 2011 14:24  Re: Как правильно работать с временными таблицами. |
|
Полезность: Нет оценки
|
Asdn пишет: | Добрый день!
Недавно стал сопровождать IBSO. В процессе разработки отчета потребовалось первоначально данные выбирать во временную таблицу.
из документации понял, что создать таблицу можно след образом
Код: |
type typeRec is record(
C_CLN_TYPE integer, -- физик/юрик
C_FILIAL [BRANCH],
C_DEPART [DEPART],
C_ORG_TYPE varchar2(10),
C_IsServiced boolean,
C_KIND_CREDIT varchar2(10)б
........
);
type data_list is table of typeRec index by integer;
RepTable data_list;
RepTableIdx integer;
|
|
Предпочитаю называть это массивами или списками, так как это ближе по смыслу.
Asdn пишет: |
хотелось бы теперь с временной таблицей работать с помощью операций SELECT, UPDATE, DELETE, LOCATE. возможно ли такое?
например, что нибудь типа
Код: |
locate tmp in RepTable
where
tmp.C_ORG_TYPE = 'SMALL' and tmp.C_IsServiced = 0;
или
select tb( tb.[Idx] : Idx )
in RepTable all
where
tb.C_CLN_TYPE = 0;
или
update tab(tab.[SUMMA] = p_nSum) in ResTable
where tab.KIND_CREDIT = 'CRED_LINE';
|
пробую так делать. выдает ошибку при компиляции.
конечно можно использовать цикл FOR, перебирать последовательно записи таблицы до искомой. получать индекс этой записи. но может существует более элегантное решение? |
Ты знаешь, можно работать и так.
По крайней мере select сделать можно.
Нужно только создать оракловский тип нужной структуры (из АРМ Администратор создаешь тип нужной структуры, потом объявляешь массив из элементов этого типа, на форме указываешь не то временный массив, не то вложенный массив) и в запросе сделать преобразование.
Вот пример:
Код: |
declare
type varr$str is varray(0) of long; -- Пользоваться лучше этой конструкцией, т.к.
-- type varr$str is varray(0) of varchar2(size) вне зависимости от size подменяется на TYPE_MEMO_TABLE, а у нее длина 4000
v varr$str;
begin
v%init('xxx');
debug_pipe('v='||v.count||'{'||v(1)||'}',0);
for ( select t(t.[column_value]:cv) in v ) loop
debug_pipe('v='||t.cv,0);
end loop;
end;
|
Подробнее можно прочитать по ключевым словам:
конвеерные функции, nested-table-функция, pipeline-функция
Другое дело, что тебе вряд ли нужно именно это
Другое решение - сделать индексацию не по числу, а по строке и использовать в качестве ключа заранее известное значение.
Код: | type data_list is table of typeRec index by varchar2(32767); |
|
|
 |
Asdn Участник
Вступление в Клуб: 04.10.2011
|
Чт Окт 20, 2011 02:32   |
|
Полезность: Нет оценки
|
А можно пример индексации? т.е. как задать для массива составной индекс и потом использовать его в Locate?
я поискал в документации, но у меня там приведены примеры с циклом For (по сути последовательный перебор).
т.е. например у меня какой то цикл For, в этом цикле я вычисляю ключ, по данному ключу нахожу подходящую запись в массиве и произвожу какие то вычисления для этой записи. и меняю значения ее полей. |
|
 |
Random Эксперт
Вступление в Клуб: 27.06.2011
|
Чт Окт 20, 2011 07:06   |
|
Полезность: 3
|
Asdn пишет: | А можно пример индексации? т.е. как задать для массива составной индекс и потом использовать его в Locate?
я поискал в документации, но у меня там приведены примеры с циклом For (по сути последовательный перебор).
т.е. например у меня какой то цикл For, в этом цикле я вычисляю ключ, по данному ключу нахожу подходящую запись в массиве и произвожу какие то вычисления для этой записи. и меняю значения ее полей. |
Еще раз: есть таблица. Структура, определенная ключевыми словами create table. Существующая в базе данных вообще.
Это уровень SQL. К нему относятся операторы SQL: select, update, insert (locate, который всё равно при компиляции PL/+ -> pl/sql преобразуется к select).
Есть запись. Структура, определенная в конкретном куске pl/sql-кода словами type is record.
Есть массив записей, определенный в конкретном куске pl/sql-кода словами type is table of index by.
Это уровень PL/SQL. К нему относятся операторы pl/sql: for .. loop и НЕ относятся операторы SQL.
Конечно, в код pl/sql включаются запросы, курсоры и прочая ересь, но при этом в процессе работы происходит переключение контекста
Так вот, когда ты пишешь SQL-запрос (select/update/insert), ты переключаешься на уровень SQL и про определенные на уровне pl/sql массивы можешь забыть. Ну, не совсем забыть, но подробнее я не буду, чтоб не путать.
Для того, чтобы было удобнее пользователям, Oracle, а следом и ЦФТ, позволили пользователям осуществлять выборку из определенным образом организованных массивов с помощью оператора SQL (одного-единственного!) select from table(имя nested-массива as тип Oracle). Эта фигня не индексируется и единственное ее достоинство - что такой запрос выполняется в одном снимке/транзакции. Ну и удобство синтаксиса.
У меня большое подозрение, что всё это вырождается при компиляции в тот же цикл for, так как быстродействие аналогичное.
то есть для того, чтобы ее создать, нужно:
1) создать тип Oracle соответствующей структуры create or replace type <имя типа> as object ...
2) создать тип Oracle create type <имя типа> as table of <имя типа из шага 1>
3) в нужном месте определить переменную типа из шага 2 (nested-массив)
4) Зачитать данные в этот массив - это делается так же, как с обычным массивом, за исключением того, что обычно nested-массив нужно а) инициализировать б) расширить до нужной размерности, хотя при select into он сам расширяется
5) читать данные уже из nested-массива, указав select from table (переменная as тип) where <условия>
Пример на pl/sql:
Код: |
drop type TMP#TABLE;
drop type TMP#TYPE;
create or replace type TMP#TYPE as object(
C_EXPRESSION VARCHAR2(2000),
C_TMP VARCHAR2(1)
);
create or replace type body TMP#TYPE as
constructor function TMP#TYPE return self as result is
begin return; end;
end;
alter type TMP#TYPE add constructor function TMP#TYPE return self as result cascade;
create or replace type TMP#TABLE as table of TMP#TYPE;
declare vvv TMP#TABLE;
begin
vvv := TMP#TABLE();
vvv.extend(100);
for i in 1 .. 100 loop
vvv(i) := TMP#TYPE('AAA'||i,'');
vvv(i).c_expression := vvv(i).c_expression||'BBB';
end loop;
for i in (select * from table(vvv)) loop
dbms_output.put_line(i.C_EXPRESSION);
end loop;
dbms_output.put_line(vvv.count);
end;
|
Читать данные с любыми условиями эта фигня будет по FullScan.
Для того, чтобы подобное организовать на PL/+, тебе:
1) нужно завести новый класс (справочник или структуру) нужной структуры.
2) завести новый массив элементов этого справочника, установив галочку "Вложенный массив".
3) в коде pl/+ определить тип type ляляля is varray(0) of [справочник]%rowtype; и использовать в коде pl/+ именно его.
так что я бы про Locate для массивов забыл и не путался.
пример работы с индексированным по строке обычному массиву:
Код: |
declare
type rec$money is record (
f_short varchar2(32767)
, f_id number
, f_name varchar2(32767)
, f_count number
);
type map$rec is table of rec$test index by varchar2(32767);
m$list map$rec;
begin
for( select a(a.[CUR_SHORT]:short$
, a.[CODE_ISO]:iso$
, a%id:id$
, a.[name]:name$
) in ::[FT_MONEY] all ) loop
m$list(a.[iso$]).f_short := a.short$;
m$list(a.[iso$]).f_id := a.id$;
m$list(a.[iso$]).f_name := a.name$;
m$list(a.[iso$]).f_count := 0;
end loop;
for (select a(a.[MAIN_V_ID]:num$) in ::[AC_FIN] all )loop
if m$list.exists(substr(a.num$,6,3)) then
debug_pipe('Счет '||a.[num$]||' открыт для валюты '||m$list(substr(a.num$,6,3)).f_name,0);
m$list(substr(a.num$,6,3)).f_count := m$list(substr(a.num$,6,3)).f_count + 1;
end if;
end loop;
end;
|
На твоем месте я завёл бы временную таблицу через ARM Администратор Словаря Данных (на уровне SQL) со временем жизни в течение сессии, заполнял бы ее своими данными и работал уже с ней, как советовали выше. |
|
 |
Asdn Участник
Вступление в Клуб: 04.10.2011
|
Пт Окт 21, 2011 04:26   |
|
Полезность: Нет оценки
|
Random, спасибо за развернутый ответ!
но к сожалению, у нас сейчас процесс становления идет. поэтому заводить собственные структуры запрещено под страхом расстрела.
эта информация останется на будущее (
а сейчас мне приходится работать просто с массивами и выкручиватся с помощью FOR.
надеюсь, что в дальнейшем перепишу на временные таблицы. |
|
 |
Random Эксперт
Вступление в Клуб: 27.06.2011
|
Пт Окт 21, 2011 07:29   |
|
Полезность: Нет оценки
|
Asdn пишет: | Random, спасибо за развернутый ответ! |
Там рядом есть кнопочка "Оценить"
Asdn пишет: | но к сожалению, у нас сейчас процесс становления идет. поэтому заводить собственные структуры запрещено под страхом расстрела. |
Заводить новые операции не запрещено?
1. есть pl/sql-вставки
2. есть execute immediate
3. PL/+ позволяет читать (но не обновлять) данные из SQL-таблиц не из модели данных, не заключая их в квадратные скобки и ставя %rowtype после наименования таблицы.
и всё это можно приспособить для insert/update обычной SQL-таблицы (не из модели данных)
Код: |
-- 1. Создаем таблицу
begin
execute immediate 'CREATE global TEMPORARY TABLE test1 (
starttestdate DATE
, endtestdate DATE
, results NUMBER
) ON COMMIT PRESERVE ROWS';
end;
-- 2. работаем с ней
declare
type ttt is table of test1%rowtype index by binary_integer;
v test1%rowtype;
a ttt;
begin
select x(x%rowtype) in test1%rowtype
into a;
-- begin pl/sql
forall i in 1 .. a.count
insert into test1 values a(i);
-- end pl/sql
end; |
|
|
 |
vek21 Участник со стажем
Вступление в Клуб: 20.09.2007
|
Пн Окт 24, 2011 13:31   |
|
Полезность: Нет оценки
|
Asdn, вы хотите работать с динамической таблицей с помощью select'oв PL/Plus? Это возможно.
Вот ваш пример(укороченный):
type typeRec is record(
C_CLN_TYPE integer, -- физик/юрик
C_DEPART [DEPART],
C_ORG_TYPE varchar2(10),
C_DAT DATE
);
type data_list is table of typeRec index by integer;
RepTable data_list;
RepTableIdx integer;
В "локальных описаниях" операции описываете функции:
---------------------------------------------------------
function GetReqD(i integer, cVar string) return DATE is -- возвращает ДАТУ из указ.эл-та динам.массива
begin
if cVar = 'C_DAT' then
return RepTable(i).C_DAT;
end if;
return null;
end;
---------------------------------------------------------
function GetReqN(i integer, cVar string) return number is -- возвращает ЧИСЛО из указ.атрибута указ.эл-та динам.массива
begin
if cVar = 'C_CLN_TYPE' then
return nvl(RepTable(i).C_CLN_TYPE, 0);
elsif cVar = 'C_DEPART' then
return nvl(RepTable(i).C_DEPART, 0);
end if;
return null;
end;
---------------------------------------------------------
function GetReqS(i integer, cVar string) return string is -- возвращает СТРОКУ из указ.атрибута указ.эл-та динам.массива
begin
if cVar = 'C_ORG_TYPE' then
return RepTable(i).C_ORG_TYPE;
end if;
return null;
end;
---------------------------------------------------------
Эти функции также необходимо описать в "глобальных описаниях" операции:
---------------------------------------------------------
function GetReqD(i integer, cVar string) return DATE; -- возвращает ДАТУ из указ.эл-та динам.массива
pragma restrict_references(GetReqD,wnds,wnps);
---------------------------------------------------------
function GetReqN(i integer, cVar string) return number; -- возвращает ЧИСЛО из указ.атрибута указ.эл-та динам.массива
pragma restrict_references(GetReqN,wnds,wnps);
---------------------------------------------------------
function GetReqS(i integer, cVar string) return string; -- возвращает СТРОКУ из указ.атрибута указ.эл-та динам.массива
pragma restrict_references(GetReqS,wnds,wnps);
---------------------------------------------------------
Понятно, что эти функции описывают доступ ко всем видам полей (числовым, строковым и даты) вашей динамической таблицы.
Далее, в начале "локальных описаний" операции пишете курсор
type cur is
select x
( x.[C_DAT] : C_DAT
, x.[C_CLN_TYPE] : C_CLN_TYPE
, x.[C_DEPART] : C_DEPART
, x.[C_ORG_TYPE] : C_ORG_TYPE
) in (
select y
( GetReqD(rownum, 'C_DAT') : C_DAT
, GetReqS(rownum, 'C_ORG_TYPE') : C_ORG_TYPE
, GetReqN(rownum, 'C_CLN_TYPE') : C_CLN_TYPE
, GetReqN(rownum, 'C_DEPART') : C_DEPART
) in ::[DUMMY]
where rownum <= RepTableIdx
)
where (1=1);
В этом курсоре, при необходимости, прописываете все группировки, сортировки и т.п.
А далее, в теле операции, уже можете использовать этот курсор:
for x in cursor Cur loop
....
end loop; |
|
 |
vek21 Участник со стажем
Вступление в Клуб: 20.09.2007
|
Пн Окт 24, 2011 13:39   |
|
Полезность: Нет оценки
|
.....
Извините, только сейчас увидел, как надо вставлять код программы...
.....  |
|
 |
|
|
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете голосовать в опросах
|
|