如何在DB2中使用嵌套结构化类型(UDT)?

时间:2010-12-30 12:33:21

标签: sql db2 user-defined-types jooq

我正在尝试使用DB2使用嵌套结构化类型(UDT),但遇到了一些问题。

以下是用于创建用例的类型,表,函数和转换的SQL语句。 每个语句都可以正常执行,但在尝试执行简单操作时会发生错误 select * from t_author

CREATE TYPE u_street_type AS (
  street VARCHAR(100),
  no VARCHAR(30)
) INSTANTIABLE MODE DB2SQL;

CREATE TYPE u_address_type AS (
  street u_street_type,
  zip VARCHAR(50),
  city VARCHAR(50),
  country VARCHAR(50),
  since DATE,
  code INT
) INSTANTIABLE MODE DB2SQL;

CREATE TABLE t_author (
  ID INT NOT NULL PRIMARY KEY,
  FIRST_NAME VARCHAR(50),
  LAST_NAME VARCHAR(50) NOT NULL,
  DATE_OF_BIRTH DATE NOT NULL,
  YEAR_OF_BIRTH INT,
  ADDRESS u_address_type
);

CREATE FUNCTION f_u_street_type_transform (street u_street_type) 
  RETURNS ROW (
    street VARCHAR(100), 
    no VARCHAR(30)
  )
  LANGUAGE SQL
  RETURN VALUES (
    street..street, 
    street..no
  );

CREATE TRANSFORM FOR u_street_type db2_program 
  (FROM SQL WITH FUNCTION f_u_street_type_transform);

CREATE FUNCTION f_u_address_type_transform (address u_address_type)
  RETURNS ROW (
    street VARCHAR(100),
    no VARCHAR(30),
    zip VARCHAR(50),
    city VARCHAR(50),
    country VARCHAR(50),
    since DATE,
    code INT
  )
  LANGUAGE SQL
  CONTAINS SQL
  NO EXTERNAL ACTION
  DETERMINISTIC
  RETURN VALUES (
    address..street..street,
    address..street..no,
    address..zip,
    address..city,
    address..country,
    address..since,
    address..code
  );

CREATE TRANSFORM FOR u_address_type db2_program 
  (FROM SQL WITH FUNCTION f_u_address_type_transform);

尝试执行select * from t_author;时出现以下错误:

The function "F_U_ADDRESS_TYPE_TRANSFORM" resolved to specific function 
"SQL101230131003100" that is not valid in the context where it is used.. 
SQLCODE=-390, SQLSTATE=42887, DRIVER=3.57.82

任何想法我做错了什么?

我正在使用DB2 v9.5(Linux)。

3 个答案:

答案 0 :(得分:3)

事实是列ADDRESS中的每个值都是标量值。如果要将结构化类型的值绑定到客户端应用程序(如DB2 CLP),因为您有一个类似“SELECT * FROM t_author”的查询,则必须使用标量转换函数,该函数将结构化值转换为单个类型的VARCHAR,CLOB或您需要的任何值。您无法通过转换函数将其扩展为多个值,因为它必须类似于多个列。 (这是不可能的,因为不同的转换函数可以返回不同数量的值,为查询提供完全不同的模式;更不用说如果您使用完全相同的查询作为具有另一个语义的子查询的问题。)< / p>

返回带有多于1列的ROW()的转换函数只能在使用外部UDF(用C / C ++或Java编写)交换结构化类型的值时使用。

p.s:我的建议是你使用常规的规范化关系数据库设计,尽量避免使用结构化类型,除非你有充分的理由这样做。

答案 1 :(得分:2)

从DB2的角度来看,jOOQ只是一个数据库应用程序。因此,数据库应用程序的所有注意事项也都与它相关。这意味着,jOOQ还需要使用具有标量函数的变换组作为变换函数。我不知道没有内置支持。

你能做的是:

  • 创建一个外部函数,它将单独的参数作为输入并将它们连接成BLOB;然后,jOOQ将分离BLOB并构造相应的Java对象
  • 将结构化类型转换为XML文档,jOOQ将解析XML文档并构造Java对象

简而言之:您必须自己保留DB2和应用程序之间传输的值中的结构信息。而且您的应用程序也必须自己相应地解释数据。所以这对你来说都是一个手动任务,就像以某种方式生成类型特定的代码一样。

不幸的是,关系数据库系统中的OO功能一般没有发展到它们非常容易和无缝使用的程度。由于它不易使用,因此只有极少数应用程序使用结构化类型。而且由于没有很多用户,因此该领域的改进不会得到高度重视。

答案 2 :(得分:1)

感谢Knut提供的信息!

我知道我必须使用标量转换函数来转换结构化值 使用客户端应用程序时(即select * from t_author)使用单值。 我通过创建一个转换函数来管理它,该函数将结构化值元素连接成一个varchar值。

这解决了从客户端应用程序检索数据的问题,但真正的原因 让这个工作正在尝试支持数据库接口libary jOOQ中的结构化类型。 使用此库表,列,存储过程,函数,结构化类型等被建模为生成的Java类。

我认为使用java.sql.Struct从java.sql.ResultSet中的结构化值列检索数据,以使用值填充生成的Java类。

当我使用转换函数时,我设法使用java.sql.Struct检索数据,将结构化类型转换为varchar值,但这不是我想要的。我希望“直接”访问结构化类型的各个元素。

有关如何完成此任务的任何提示?