2

我正在尝试使用 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)。

4

3 回答 3

4

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

仅当与外部 UDF(用 C/C++ 或 Java 编写)交换结构化类型的值时,才能使用返回超过 1 列的 ROW() 的转换函数。

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

于 2010-12-30T13:03:14.187 回答
2

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

你可以做的是:

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

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

不幸的是,关系数据库系统中的面向对象特性通常还没有发展到真正容易和无缝使用的地步。因为它不容易使用,所以只有极少数应用程序使用结构化类型。而且由于用户不多,因此该领域的改进不会得到高度重视。

于 2011-01-04T12:08:22.330 回答
1

感谢克努特提供的信息丰富的回答!

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

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

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

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

关于如何做到这一点的任何提示?

于 2011-01-04T11:23:07.617 回答