是否可以 return MySQL 存储过程中(可变)数量的选择的 UNION 的单个结果集而不使用 EXECUTE?

Is it possible to return a single result set of the UNION of a (variable) number of selects in a MySQL stored procedure without using EXECUTE?

我正在 MySQL 中创建一个存储过程,给定一个域名,应该对域名中的每个 "level" 进行一个 select 查询(全部相同table、returning 相同的字段)和 return 这些查询结果的 UNION 作为单个结果集。

由于查询是在循环中执行的(即查询的数量取决于作为存储过程的参数提供的域名中的级别数),我不能只使用静态 SQL包含多个 select 的语句,它们之间有 UNION。

相反,我需要迭代地进行 select 查询,或者在这个循环中构建一个连接的 SQL 查询字符串,并在循环后执行它。

后一种解决方案(串联的 SQL 语句)对我来说既 "ugly" 又 "dangerous" (安全方面),因此我更愿意这样做 "natively" 不知何故,但我不确定这是否可能?

我想我可以使用 temp tables 在每个循环迭代中存储查询结果,但后来我陷入了如何最终联合所有这些内容的问题temp tables(记住:每次调用我的存储过程都会有这些 temp tables 的变体编号)而不最终使用 EXECUTE? (与从头开始构建整个 multi-UNION SQL 语句并执行此语句相比,使用 EXECUTE 当然更不丑陋且风险更低,但我仍然很好奇是否真的需要 EXECUTE 来完成这个?)

有没有人对此用例有任何类型的 elegant/recommended 解决方案(我认为毕竟这一定至少不是太罕见?)?

到目前为止,这是我的功能,以防万一有人好奇或认为它可以让他们更好地了解我的问题:

CREATE lookup_domain(IN lookup_name VARCHAR(4096))
BEGIN
    DECLARE noof_levels int(11) DEFAULT 0;
    DECLARE remaining_levels varchar(4096) DEFAULT '';
    SET noof_levels = ROUND((LENGTH(lookup_name)-LENGTH(REPLACE(lookup_name, ".", ""))) / LENGTH("."));
    SET remaining_levels = lookup_name;
    WHILE noof_levels >= 1 DO
        SET  noof_levels = noof_levels - 1; 
        #This will simply print the current domain level
        #but in reality it will look up properties of it in a table,
        #like: SELECT name, prop1, prop2, prop3 FROM domains WHERE name = ?
        #and it's these results that I want to UNION into a single result set
        SELECT remaining_levels AS 'debug_res';
        SET remaining_levels = SUBSTRING(remaining_levels,LOCATE('.', remaining_levels)+1);
    END WHILE;
END

因此,使用参数 "some.test.domain.com" 调用此函数的所需(单个)结果集应该类似于:

------------------------------------------------
| name                 | prop1 | prop2 | prop3 |
------------------------------------------------
| some.test.domain.com | ...   | ...   | ...   |
| test.domain.com      | ...   | ...   | ...   |
| domain.com           | ...   | ...   | ...   |
------------------------------------------------

在该过程的开头,创建一个临时 table,其中包含您将要 return 的输出列的定义。临时 table 命名空间的范围是会话(数据库连接),因此不可能有两个并发的 运行 过程导致该名称发生冲突。

-- in case it is there from a previous run if the proc in the same session
DROP TEMPORARY TABLE IF EXISTS tmp_lookup;
-- define the columns for the output
CREATE TEMPORARY TABLE tmp_lookup (name ...
-- the above statements go before this next line
SET noof_levels = ...

然后,在循环中,将SELECT更改为INSERT ... SELECT,将结果写入临时table,而不是立即发送给客户端。

INSERT INTO tmp_lookup SELECT name...

END WHILE;之后,return所有收集到的行给调用者:

SELECT * FROM tmp_lookup;