Как использовать вывод таблицы из хранимой процедуры MYSQL

Я искал последний час или около того и не нашел убедительного ответа на эту, казалось бы, простую проблему:

Как вы вызываете хранимую функцию/процедуру 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 ;

Как пример. Мне было бы неплохо использовать хранимую функцию.

Ответы

Ответ 1

Это невозможно сделать напрямую, поскольку вывод неограниченного выбора в хранимой процедуре - это набор результатов, отправленный клиенту, но не технически таблица.

Обходной путь заключается в том, чтобы позволить proc поместить данные во временную таблицу после создания таблицы для вас. Эта таблица будет доступна только для вашего соединения, когда процедура завершится. Это не вызовет конфликта, если кто-то еще запускает proc в одно и то же время и не будет видимым для какого-либо другого соединения.

Добавьте это в процедуру:

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

Когда ваша процедура закончится, SELECT * FROM foo; предоставит вам то, что вы получили от proc. Вы можете присоединиться к нему почти так же, как и любой стол.

Когда все будет готово, отбросьте его, или он исчезнет сам по себе, когда вы отключитесь. Если вы снова запустите proc, он будет сброшен и воссоздан.

Ответ 2

Вот конкретный пример в MySql 8, основанный на предложении @Michael-sqlbot:

-- 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 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 usable
select * from tmpSomedata ;

Который производит:

itemCat|itemsTot|lowestQty|highestQty|
-------|--------|---------|----------|
      1|      10|        1|         9|
      2|       1|        0|         1|
      3|      66|        7|        50|
      5|      12|       12|        12|