powered by simpleCommunicator - 2.0.59     © 2025 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / IBM DB2, WebSphere, IMS, U2 [игнор отключен] [закрыт для гостей] / DB2 - вопросы по возврату TABLE из функции, UDT, курсорам, временным таблицам.
5 сообщений из 5, страница 1 из 1
DB2 - вопросы по возврату TABLE из функции, UDT, курсорам, временным таблицам.
    #37723929
kalupator
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Добрый день. Осуществляю переезд с Oracle на DB2 - соответственно перенос ХП, функций и изменения в клиентском приложении. Возник ряд трудностей, уже несколько дней борюсь - прошу Вашей помощи.
Есть ограничения клиентского приложения - нет всего исходного кода, поэтому обращение к базе только реализованными методами:
-нельзя делать вызов ХП через call, вызов функций только через запросы вида select f_name() from dual;
соответственно все реализуется только на функциях. внутри функций можно вызывать ХП.

Основная задача написать универсальную функцию - на вход табличной функции приходит текст запроса: select 4 полей (поля разные, таблицы разные, но поля всегда 4). (число 4 для примера, на самом деле около 20.) На выходе соотв. таблица, полученная путем выполнения данного запроса.

Очень не хочется делать через временные таблицы, хочется получать результат табличной функцией.

Пытался вернуть значение табличной функции 3мя способами:
-через User Defined Type
-через явный курсор
-через неявный курсор (return select...)

Но ничего не вышло, посему возникли следующие вопросы:

1. Вопрос по пользовательским типам

Возможно ли определить User Defined Type, затем массив таких типов и возвращать его как результат табличной функции?
Не получается не то, что массив, даже одиночную типизированную запись вернуть результатом функции.

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
CREATE TYPE VAR_T
  AS
(
    FLD1 CHARACTER(254),
    FLD2 CHARACTER(254),
    FLD3 CHARACTER(254),
    FLD4 CHARACTER(254)
)
  MODE DB2SQL
  ;

CREATE OR REPLACE FUNCTION fname()
RETURNS TABLE (
    FLD1 CHARACTER(254),
    FLD2 CHARACTER(254),
    FLD3 CHARACTER(254),
    FLD4 CHARACTER(254)
)
LANGUAGE SQL
BEGIN ATOMIC
    DECLARE F_REC REF(VAR_T);
    SET F_REC.FLD1 = 'a';
    ...
    RETURN F_REC;
END;


автор "F_REC.FLD1" недопустимо в контексте, где оно используется. LINE NUMBER=31. SQLSTATE=42703

2. Возможно ли в табличной функции использовать курсоры?

3. Если да, то возможно результатом табличной функции сделать курсор? Либо записи отобранные курсором, поместить в типизированную переменную и вернуть через result.


Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
CREATE OR REPLACE FUNCTION FNAME(sel_sql VARCHAR(4000))
RETURNS TABLE (
    FLD1 CHARACTER(254),
    FLD2 CHARACTER(254),
    FLD3 CHARACTER(254),
    FLD4 CHARACTER(254)
)
LANGUAGE SQL
  
BEGIN ATOMIC
  DECLARE C1 CURSOR WITH HOLD FOR S1;
  PREPARE S1 FROM sel_sql;
  OPEN C1;
  RETURN C1;
END;



4. Возможно ли как-то получить результат табличной функции таким способом?

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
CREATE OR REPLACE FUNCTION FNAME(sel_sql VARCHAR(4000))
RETURNS TABLE (
    FLD1 CHARACTER(254),
    FLD2 CHARACTER(254),
    FLD3 CHARACTER(254),
    FLD4 CHARACTER(254)
)
LANGUAGE SQL
  
BEGIN ATOMIC
  RETURN select * from (sel_sql);
END;



получю
авторSQL0104N Обнаружен неправильный элемент ")" после текста "lect * from (sel_sql". Список возможных правильных элементов: "<join_type_without_spec> JOIN <join_operand>". LINE NUMBER=11. SQLSTATE=42601

НО когда я жестко в коде зашиваю
RETURN select * from (select f1,f2,f3,f4 from table1);
все супер! .

5. Если я использую Global Temporary Table (структура всегда одинаковая, свой tablespace) ее лучше каждый раз создавать в процедуре, функции либо один раз и навсегда создать а в функциях лишь заполнять\очищать? просто во втором варианте непонятно, чем она лучше обычной таблицы.

P.S. Прошу прощения за большое кол-во текста - хотелось максимально информативно объяснить проблемы.
...
Рейтинг: 0 / 0
DB2 - вопросы по возврату TABLE из функции, UDT, курсорам, временным таблицам.
    #37724402
mustaccio
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
То есть вы хотите использовать табличную функцию вместо F_NAME()?
Код: sql
1.
select f_name() from dual;



Не получится - табличные функции можно использовать только в таком контексте:
Код: sql
1.
select * from table (f_name());



Потом, кажется, курсоры в теле табличных функций (на SQL) не разрешены.

DB2 на какой платформе?
...
Рейтинг: 0 / 0
DB2 - вопросы по возврату TABLE из функции, UDT, курсорам, временным таблицам.
    #37724961
kalupator
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
mustaccio,

авторselect * from table (f_name());

такой вариант меня прекрасно устраивает =) вопрос только как выполнить пришедший строкой запрос выборки в функцию и вернуть его результатом табличной функции, если в табличных функциях нельзя использовать курсоры, execute и т.д.

в Oracle было проще. был структурированный тип
CREATE OR REPLACE TYPE "SOME_T" as object
Код: plsql
1.
2.
3.
4.
5.
(
  fld1 char(254),
  fld2 char(254),
  fld3 char(254),
  fld4 char(254))



и тип абстрактной таблицы вышеуказанного типа.
Код: plsql
1.
CREATE OR REPLACE TYPE "SOME_T_TABLE" as [color=red]TABLE [/color]of SOME_T;



дальше была функция
Код: plsql
1.
function fname (sel_sql varchar2(4000)) return SOME_T_TABLE;



в функции объявлялся массив вышеуказанного типа
res SOME_T_TABLE := SOME_T_TABLE();

открывался курсор for sel_sql и производилось наполнение массива.

получение результата
return res;

вызов
авторselect * from table (f_name());

Пытаюсь что-нибудь подобное реализовать на db2 без временных таблиц.
Попробую покурить типизированные массивы UNNEST.

db2 пока под win, но планируется перенос под ос\400.
...
Рейтинг: 0 / 0
DB2 - вопросы по возврату TABLE из функции, UDT, курсорам, временным таблицам.
    #37725376
Mark Barinstein
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
kalupatorОсновная задача написать универсальную функцию - на вход табличной функции приходит текст запроса: select 4 полей (поля разные, таблицы разные, но поля всегда 4). (число 4 для примера, на самом деле около 20.) На выходе соотв. таблица, полученная путем выполнения данного запроса.Если при каждом вызове количество и тип полей всегда одинаков, то вам поможет функция на внешнем языке, таком как C или JAVA.
Самый простой способ - на JAVA, т.к. можно скомпилировать на win и использовать тот же самый class файл и для win, и для os/400.
Там достаточно просто всё.

Unvsl_Tab.java
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
import COM.ibm.db2.app.UDF;
import java.sql.*;
import java.text.*;

public class Unvsl_Tab extends UDF {
  static final int OUT_IDX = 1;
  static final SimpleDateFormat DATF = new SimpleDateFormat("yyyy-MM-dd");
  static final SimpleDateFormat TMSF = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
  static final DecimalFormat DECF = new DecimalFormat("#################################0.##################################");
  
  static {
    DECF.setDecimalFormatSymbols(new DecimalFormatSymbols(java.util.Locale.US));
    DECF.setGroupingUsed(false);
  }
	
  Connection con = null;
  Statement st = null;
  ResultSet rs = null;
  boolean isNext = false;

  public void unvsl_tab (
// input - select statement
    String stmt 
/* 
   Output fields.
   Their number and data types must correspond to the fields 
   of the select statement above
 */
  , String               __String
  , int                  __Int
  , String               __Timestamp
  , String               __Date
  , java.math.BigDecimal __Decimal
  , String               __Decfloat
  ) throws Exception {
    switch (getCallType()) {
      case UDF.SQLUDF_TF_FIRST:
        con = getConnection();
        con.setAutoCommit(false);
        break;
      case UDF.SQLUDF_TF_OPEN:
        st = con.createStatement();
        rs = st.executeQuery(stmt);
        isNext = rs.next();
        break;
      case UDF.SQLUDF_TF_FETCH:
        if (isNext) {
// sequence of 'set' functions which corresponds to the output fields
          String f1 = rs.getString(1);
      	  if (!rs.wasNull()) set(OUT_IDX + 1, f1);

      	  int f2 = rs.getInt(2);
      	  if (!rs.wasNull()) set(OUT_IDX + 2, f2);

      	  Timestamp f3 = rs.getTimestamp(3);
      	  if (!rs.wasNull()) set(OUT_IDX + 3, TMSF.format(f3));

      	  Date f4 = rs.getDate(4);
      	  if (!rs.wasNull()) set(OUT_IDX + 4, DATF.format(f4));

     	  java.math.BigDecimal f5 = rs.getBigDecimal(5);
      	  if (!rs.wasNull()) set(OUT_IDX + 5, f5);

      	  java.math.BigDecimal f6 = rs.getBigDecimal(6);
      	  if (!rs.wasNull()) set(OUT_IDX + 6, DECF.format(f6));
// end of the sequence
      	  isNext = rs.next();
        } else 	
      	  setSQLstate("02000");
        break;
      case UDF.SQLUDF_TF_CLOSE:
        if (rs != null) {rs.close(); rs = null;}
        if (st != null) {st.close(); st = null;}
        break;
      case UDF.SQLUDF_TF_FINAL:
        if (con != null) con.close();
        break;
    }
  }
 
}

Всё что вам надо изменить там, это для возвращаемых полей переписать "выходные" параметры главного метода согласно:
Supported SQL data types in DB2GENERAL routines
и соответственно изменить набор вызовов 'set' для каждого типа поля в select.
В примере - работа с разными типами полей.

Потом из db2cw компилируете класс:
Код: plaintext
"%db2path%"\java\jdk\bin\javac Unvsl_Tab.java
и появившийся Unvsl_Tab.class помещаете в "%db2path%"\function.
Создаёте функцию:
Unvsl_Tab.ddl
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
CREATE FUNCTION UNVSL_TAB (stmt varchar(4000))
RETURNS TABLE (
  v_str		varchar(50)
, v_int		int
, v_timestamp	timestamp
, v_date	date
, v_decimal	decimal(31, 5)
, v_desfloat    varchar(36)
)
LANGUAGE java 
DETERMINISTIC 
FENCED 
READS SQL DATA
DISALLOW PARALLEL
FINAL CALL
NO EXTERNAL ACTION
EXTERNAL NAME 'Unvsl_Tab.unvsl_tab' 
PARAMETER STYLE db2general


и работаете:
Код: sql
1.
select * from table(unvsl_tab('values (''1'', 1, current timestamp, current date, 1234.5678, decfloat(''1234567890123456789012345678901234''))'))


Если же у вас при каждом вызове будет разный набор полей и их типы, то в этой версии так делать нельзя.
...
Рейтинг: 0 / 0
DB2 - вопросы по возврату TABLE из функции, UDT, курсорам, временным таблицам.
    #37727684
kalupator
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
спасибо, будем пробовать
...
Рейтинг: 0 / 0
5 сообщений из 5, страница 1 из 1
Форумы / IBM DB2, WebSphere, IMS, U2 [игнор отключен] [закрыт для гостей] / DB2 - вопросы по возврату TABLE из функции, UDT, курсорам, временным таблицам.
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]