如何将查询结果传递给同一部分的函数?

时间:2015-10-13 14:07:27

标签: sql linux informix stored-functions

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

假设表mytablevalue 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?

1 个答案:

答案 0 :(得分:0)

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

设置

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

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演示数据库'stores'有一个与{{1}同构的表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

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

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

这会产生6种元素的结果(镁, 锰, 䥑, 钔, 钼, Moscovium:Mercury没有计算,因为它的符号是Hg,它不是以M)和8个状态开始,如48行一样。

要执行的查询的调整类似于:

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

然而,这不起作用,产生错误:

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(…)表达式中对函数进行多次调用的一组表结果。但这不是SQL在SQL中的工作方式。它们应该是“固定的”。函数的常量参数产生一个结果集,看起来像一个表。但是尝试使用不同的参数多次调用它并处理结果集(最多)会很棘手 - 这不是SQL的工作方式。

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

我尝试了多种变体。例如,假设您创建GROUP_CONCAT aggregate,则可能需要尝试:

TABLE(…)

但这会产生:

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

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

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