如何将查询结果传递给相同的函数?

Posted

技术标签:

【中文标题】如何将查询结果传递给相同的函数?【英文标题】:How to pass result of query to function being part of the same? 【发布时间】:2015-10-13 14:07:26 【问题描述】:

这适用于 Linux 上的 Informix 11.70.FC6GE。

假设表 mytable 具有列 value varchar(16) 和如下函数:

create function myfunc(str varchar(16)) returning varchar(16)
  define result varchar(16);

  while (<some-condition>)
    let result = ...;
    return result with resume;
  end while;

end function;

当我这样做时

select * from mytable, table(myfunc(value)) vt(result);

我明白了

Not implemented yet. [SQL State=IX000, DB Errorcode=-999]

... - :-S.

在做

select * from mytable, table(myfunc('some literal')) vt(result);

有效。

有没有机会在给定的环境中实现这一点?如果不是:我需要切换到哪个版本的 Informix?

【问题讨论】:

您使用的是哪个版本的 Informix? 我怀疑您的问题是指“版本”,即 Informix Growth Edition V11.70 @JonathanLeffler 我对 11.70 与 12.10 或许多旧版本之一感兴趣。在这种情况下,该版本几乎没有什么不同。我得试验一下。我怀疑问题与执行相关查询有关,但试图将其中一个表视为变量。我什至没有好词来形容它。 对于为这个问题创建答案的巨大延迟感到抱歉。 【参考方案1】:

我认为没有办法做你想做的事;我确信没有一种简单的方法可以做类似的事情。

设置

考虑一个包含两个表的数据库:一个(化学)元素表 - 元素周期表 - 和一个(美国)州表。

CREATE TABLE elements
(
    atomic_number   INTEGER NOT NULL PRIMARY KEY
                    CHECK (atomic_number > 0 AND atomic_number < 120),
    symbol          CHAR(3) NOT NULL UNIQUE,
    name            CHAR(20) NOT NULL UNIQUE,
    atomic_weight   DECIMAL(8, 4) NOT NULL,
    pt_period       SMALLINT NOT NULL
                    CHECK (pt_period BETWEEN 1 AND 7),
    pt_group        CHAR(2) NOT NULL
                    -- 'L' for Lanthanoids, 'A' for Actinoids
                    CHECK (pt_group IN ('1', '2', 'L', 'A', '3', '4', '5', '6',
                                        '7', '8', '9', '10', '11', '12', '13',
                                        '14', '15', '16', '17', '18')),
    stable          CHAR(1) DEFAULT 'Y' NOT NULL
                    CHECK (stable IN ('Y', 'N'))
);

CREATE TABLE US_States
(
    code    CHAR(2) NOT NULL PRIMARY KEY,
    name    VARCHAR(15) NOT NULL UNIQUE
);

我假设您可以使用正确的数据填充这两个表(请参阅 Web Elements 以了解元素周期表;Informix 演示数据库“商店”有一个表 state 与此处使用的 US_States 表同构) .

现在考虑一个过程states_starting()

CREATE FUNCTION states_starting(initial CHAR(1)) RETURNING VARCHAR(15);

    DEFINE result VARCHAR(15);

    FOREACH SELECT Name
              INTO result
              FROM US_States
              WHERE Code[1] = initial
              ORDER BY Name
        RETURN result WITH RESUME;
     END FOREACH;

END FUNCTION;

调整问题中的查询

我有点惊讶vt(result) 表示法有效——但它确实有效,指定了一个表别名vt 和列名result。因此,有效的查询的改编是:

SELECT *
  FROM Elements, TABLE(states_starting('M')) vt(result)

这会生成 118 个元素和 8 个状态的笛卡尔积,名称以“M”开头,共 944 行。一个稍微合理的查询是:

SELECT *
  FROM Elements JOIN TABLE(states_starting('M')) AS vt(result)
    ON Elements.Symbol[1] = vt.result[1]
 ORDER BY Elements.Atomic_Number

这会生成 6 种元素的结果(镁、 锰, 迈特里姆, 钔, 钼, Moscovium:水星没有出现,因为它的符号是 Hg,它不以 M 开头)和以前的 8 个状态,共 48 行。

您要执行的查询的适配如下所示:

SELECT *
  FROM Elements AS e
  JOIN TABLE(states_starting(e.name[1])) AS vt(result)
    ON Elements.Symbol[1] = vt.result[1]
 ORDER BY Elements.Atomic_Number

这不起作用,但是会产生错误:

-217: Column (name) not found in any table in the query (or SLV is undefined).

这与问题中的错误不同;我无法复制它。但这是该查询面临的问题的症状。

问题是在TABLE(…) 中,名称e 是未知的,但从参数中删除e. 并不会改变事情。

此外,要生成完整的“正确”结果,TABLE(…) 表达式必须被计算多次,每个单独的首字母计算一次。因此,您需要在 TABLE(…) 表达式中使用不同参数多次调用该函数的一组表结果。但这不是表在 SQL 中的工作方式。它们应该是“固定的”。函数的常量参数产生一个结果集,看起来像一个表。但是尝试使用不同的参数多次调用它并处理结果集(充其量)会很棘手——这不是 SQL 的工作方式。

我对这个解释并不完全满意。我试图表达的想法几乎可以肯定是查询不起作用的原因,但我不高兴我解释得很好。

我尝试了多种变体。例如,假设您创建了一个GROUP_CONCAT aggregate,您可能想尝试:

SELECT group_concat(states_starting(a))
  FROM (SELECT DISTINCT NAME[1] AS a FROM us_states)
 GROUP BY a

但这会产生:

-686: Function (states_starting) has returned more than one row.

我认为从函数结果创建 SET 或 LIST 没有帮助。


在 Mac OS X 10.11.5 和 Informix 12.10.FC6(以及 ClientSDK 4.10.FC6 和 SQLCMD 90.01 — 与 Microsoft 的同名 johnny-come-lately 无关)上进行测试。

【讨论】:

以上是关于如何将查询结果传递给相同的函数?的主要内容,如果未能解决你的问题,请参考以下文章

如何将结构传递给 c++ 函数并通过一些修改返回相同的结构?

如何将内部回调的结果传递给其父函数? [复制]

如何按值传递sql函数参数

C ++:将对象按值传递给同一类的成员函数

C ++编译器能否优化使用用于将函数结果传递给另一个函数的虚拟变量?

SQL Server - 将表传递给函数......如何?这是个好主意吗?