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

Posted

技术标签:

【中文标题】如何在 DB2 中使用嵌套结构化类型 (UDT)?【英文标题】:How to use nested structured types (UDT's) in DB2? 【发布时间】:2011-06-01 13:08:49 【问题描述】:

我正在尝试通过 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)。

【问题讨论】:

【参考方案1】:

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

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

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

【讨论】:

【参考方案2】:

感谢 Knut 提供的信息丰富的回答!

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

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

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

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

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

【讨论】:

【参考方案3】:

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

你可以做的是:

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

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

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

【讨论】:

很好的反馈,谢谢!这就是我们 jOOQ 所担心的:使用 UDT 的某些东西在许多 RDBMS 中开始了,但从未正确完成或继续。另一方面,Oracle 对 UDT 及其在 JDBC 中的集成有很强的支持。所以我期待在 DB2 中看到类似的东西......我们将看到未来会带来什么

以上是关于如何在 DB2 中使用嵌套结构化类型 (UDT)?的主要内容,如果未能解决你的问题,请参考以下文章

如何批量收集到子查询中的 UDT 类型

Cassandra 中的用户定义类型 (UDT) 行为

嵌套SQL语句訪问DB2中SQLCA的调用技巧

通过 Spark SQL 查询 Cassandra UDT

Db2 中的嵌套联接

Cassandra - 如何使用 map<text, uuid> 在 UDT 上执行 Solr 查询