19

我一直在寻找最后一个小时左右,并没有找到这个看似简单的问题的结论性答案:

如何调用存储的 MYSQL 函数/过程并在进一步的 SELECT 查询中使用其输出?


虽然这显然不起作用,但这是我想要的那种东西:

SELECT P.`id` FROM (CALL test_proc()) AS P

其中 test_proc() 定义为:

DROP PROCEDURE IF EXISTS test_proc;
DELIMITER ;;
CREATE PROCEDURE test_proc()
BEGIN
    SELECT * FROM `table`;
END;;
DELIMITER ;

举个例子。我也可以使用存储函数。

4

3 回答 3

21

这不能直接完成,因为存储过程中无界选择的输出是发送给客户端的结果集,但从技术上讲不是表。

解决方法是让 proc 在为您创建表后将数据放入临时表中。此表仅在过程完成后对您的连接可用。如果其他人同时运行 proc 并且不会对任何其他连接可见,则不会导致冲突。

将此添加到过程中:

DROP TEMPORARY TABLE IF EXISTS foo;
CREATE TEMPORARY TABLE foo SELECT ... your existing select query here ...;

当您的程序完成时,SELECT * FROM foo;将为您提供您从 proc 中获得的内容。你可以像任何桌子一样加入它。

完成后,将其放下,否则当您断开连接时它会自行消失。如果再次运行 proc,它将被删除并重新创建。

于 2013-08-01T05:10:54.300 回答
2

根据@Michael-sqlbot 的建议,这是 MySql 8 中的一个具体示例:

-- Create some test data
drop table if exists someData ;
create table someData (itemId int, itemName varcharacter(20), itemQty int, itemCat int) ;
insert into someData values
(1,'First', 9, 1)
,(2,'Second',50, 3)
,(3,'Third', 12, 5)
,(4,'Fourth', 7, 3)
,(5,'Fifth', 1, 2)
,(6,'Sixth', 1, 1)
,(7,'Seventh', 9, 3)
,(8,'Eighth', 0, 2)
;

-- Just checking that it's all there!
select * from someData ;

-- Define the proc
delimiter //
drop procedure if exists prcSomeData //
create procedure prcSomeData()
    comment 'Create a temporary table called "tmpSomeData"'
begin
    drop table if exists tmpSomeData ;
    create temporary table tmpSomeData as
        select itemCat
            , sum(itemQty) as 'itemsTot'
            , min(itemQty) as 'lowestQty'
            , max(itemQty) as 'highestQty'
            from someData
            group by itemCat
            order by itemCat
        ;
end //
delimiter ;

-- Gotta run the proc to instantiate the temp table
call prcSomeData() ;        -- produces a temporary table "tmpSomeData", exists for the session
-- Now it's usable
select * from tmpSomedata ;

产生:

itemCat|itemsTot|lowestQty|highestQty|
-------|--------|---------|----------|
      1|      10|        1|         9|
      2|       1|        0|         1|
      3|      66|        7|        50|
      5|      12|       12|        12|
于 2019-09-07T01:39:18.253 回答
0

更好的解决方案是在存储过程之外创建临时表,并让过程更新/插入到它。这样多次调用的结果可以存储在一个表中(只要插入了相同的列),最后用一个简单的SELECT.

这是一个使用与上述#sinecospi 相同的数据的示例:

/* The data */
drop table if exists someData ;
create table someData (itemId int, itemName varchar(20), itemQty int, itemCat int) ;
insert into someData values
(1,'First', 9, 1)
,(2,'Second',50, 3)
,(3,'Third', 12, 5)
,(4,'Fourth', 7, 3)
,(5,'Fifth', 1, 2)
,(6,'Sixth', 1, 1)
,(7,'Seventh', 9, 3)
,(8,'Eighth', 0, 2);

/* The stored procedure */
DROP PROCEDURE IF EXISTS sproc;

DELIMITER //

CREATE PROCEDURE sproc(
  IN fld CHAR(64),
  IN tbl CHAR(64)
)

BEGIN
  SET @s = CONCAT('INSERT INTO results
    SELECT \'',fld,'\' AS fld, x.* FROM (
      SELECT ',fld,' AS bin, COUNT(',fld,') AS ct 
          FROM ',tbl,' 
          GROUP BY bin 
          ORDER BY bin) x;');
  PREPARE stmt FROM @s;
  EXECUTE stmt;
  DEALLOCATE PREPARE stmt;
  
END //

DELIMITER ;

/* Calls */

CREATE TEMPORARY TABLE IF NOT EXISTS results (
  fld VARCHAR(30), bin VARCHAR(30), ct FLOAT);


CALL sproc('itemQty','someData');
CALL sproc('itemCat','someData');

SELECT * FROM results;

最后,临时表results有 2 个调用的输出。

于 2020-10-16T19:04:06.493 回答