I have execute only access to a stored procedure.
This SP seems to select some data from multiple tables, and returns one row. I need to store two columns of the output of this SP into a table.
Is there any way to do this within MySQL?
If it returns a row, this is a stored function and not a stored procedure. You can use something like the following to insert into your table:
INSERT INTO tablename SELECT (SELECT col1, col2 FROM (SELECT somefunction()))
Otherwise, it will be a stored procedure and you should do something like this, assuming that #var1 and #var2 are output parameters:
CALL someprocedure(#var1, #var2, #var3)
INSERT INTO tablename SELECT(#var1, #var2)
See the documentation about Create Procedure and Create Function for more information about functions versus procedures.
MySQL has an extension to stored procedures that allows the procedure to return one or more result sets to the client, as if the client had issued a SELECT query... but those results are ephemeral. They don't persist and they can't be stored in variables or otherwise accessed after the procedure finishes -- they can only be "fetched" the one time.
There is a way to make them accessible without breaking the way the procedure already works, as I discussed here, but you can't do it without a change to the procedure:
How to use Table output from stored MYSQL Procedure
The idea is for the procedure to write its output in a temporary table, and then return it to the caller by calling SELECT against the temporary table -- but to leave the temporary table behind so that the caller can access it directly if desired.
That's not exactly the same as what you're asking though, which is why I didn't mark this question as a duplicate, since you, unlike the other poster, do not appear to have administrative control of the procedure... but unless you can make the case for a change like this, there's not another way within MySQL to access those returned values, since they only exist in the result-set that's returned.
Of course, procedures do have optional OUT parameters, where you can hand variables to the procedure as part of arguments you use to call it, and it can set those variables, so that they'll have the values you need when the procedure is done, but that only works when the return values are scalars and would require a change to the procedure's interface, since procs in MySQL do not have "optional" arguments... if the procedure were changed to permit this, it would require an increased number of arguments to be provided every time it was called, and if other components are calling it, that could easily break other things.
Related
In SQL Server, I used to create a table variable to store results from a certain stored procedures. This is how I usually do with table variable.
DECLARE #My_Table_Variable TABLE(col_1 FLOAT, col_2 FLOAT)
INSERT INTO #My_Table_Variable(col_1, col_2) EXEC [My_Procedure]'param_1','param_2'
Now, while using MySQL, I recognized that table variable doesn't exist. I've seen some questions related to this, for instance, this one says it's not possible to SELECT something FROM a procedure.
How about temporary table? Can we CALL a procedure, and then put the result into a temporary table? With the syntax something like this:
CALL my_procedure('my_first_parameter','my_second_parameter') INTO my_temporary_table;
which allows me to query from my_temporary_table. Is this possible to be performed?
I know this question has been discussed quite a lot here. But I have a particular case when I need to pass a list of parameters (comma - separated) which prevents me to have a local variable declared and used for input parameter.
As pointed out in the above discussion, it is suggested to declare a local variable and assign the parameters to this variable. However, what should I do in case my parameter is of type Text and can be comma - separated list?
For example -
CREATE DEFINER=`Admin`#`%` PROCEDURE `MyReport`(
p_myparameter_HK Text
)
BEGIN
SELECT
*
FROM MyTable
WHERE
(find_in_set(MyTable.column_HK, p_myparameter_HK) <> 0 OR MyTable.column_HK IS NULL)
;
END
Performance:
Query
If I just run the query - 300 ms
Stored Procedure
CALL MyReport('0000_abcd_fake_000')
This procedure keeps running endlessly.
My question is, how can I disable parameter sniffling and use local variable instead of find_in_set to match the query performance.
The times that I have needed to pass an arbitrary list of things to a Stored Procedure, I did it this way:
CREATE (or already have) a TABLE for passing the info in. Both the caller and the Procedure know the name of the procedure. (Or it could be passed in, but adds some messy "prepare-executes".)
Do a bulk INSERT into that table. (INSERT INTO tbl (a,b) VALUES (...), (..), ...;)
Perform JOINs or whatever to use the table efficiently.
In my case, the extra effort was worth it.
Consider a general scenario
I have a stored procedure which returns a specific value at the end. Do I need to explicitly mention it as out parameter? Or is the select statement enough to return the value?
You can construct and call different types of stored procedures:
1) A stored procedure that returns no result. For example, such a stored procedure can log non-critical information, or change database data in a straightforward way.
Example : A stored procedure which performs insert operation.
2) A stored procedure that returns one or more values using output parameters. For example, such a procedure can indicate success or failure, or retrieve and return data items.
Example : A stored procedure which performs "Select particular_field
FROM table ..." query.
3) A stored procedure that returns one or more result sets. The procedure can execute one or more queries, each of which returns an arbitrary number of rows. Your application loops through each result set to display, transform, or otherwise process each row in it.
Example : A stored procedure which performs multiple select queries.
Hope it might help.
I have MySQL procedure where I want to get a result of query:
SELECT id FROM mbus_clients WHERE second_name like surnamePart AS
So it should be an array. The decision I've found in the internet is to use temporary table.
But how can I return a table and read with PHP? Is it ok?
Simply call the procedure:
CALL procedurename();
If the procedure performs a SELECT, the result set of the procedure call will be the same as if you'd performed the query itself. You can then fetch the rows using PHP the same way as if you'd performed a SELECT.
I have a procedure that creates a table, is it possible to have a view (or similar) that can call the procedure then select from the table?
I've tried this:
DELIMITER $$
CREATE DEFINER=`root`#`localhost` FUNCTION `new_routine`(p1 INT) RETURNS int(1)
BEGIN
CALL rMergeDateFields();
RETURN 1;
END
CREATE VIEW `db`.`vIntervals` AS
SELECT new_routine(0) AS col1;
SELECT * FROM MergedData;
but I get this error
Error 1422: Explicit or implicit commit is not allowed in stored function or trigger.
Any ideas?
No, you cannot. Views are typically read-only operations; and that behavior cannot be guaranteed if stored-procedures are invoked.
Related question:
How to call Stored Procedure in a View?
Is it possible to call stored procedure in view?
Here is a canonical resource:
http://dev.mysql.com/doc/refman/5.1/en/view-updatability.html
Some views are updatable. That is, you can use them in statements such as UPDATE, DELETE, or INSERT to update the contents of the underlying table. For a view to be updatable, there must be a one-to-one relationship between the rows in the view and the rows in the underlying table. There are also certain other constructs that make a view nonupdatable.
As invoking the stored procedure cannot assure 1:1 relationships with view rows, the update is not permitted.
You can't do this from a view, but a stored procedure itself can return a result set.
DELIMITER $$
CREATE DEFINER=`root`#`localhost` PROCEDURE `merge_and_select` ()
BEGIN
CALL rMergeDateFields();
SELECT * FROM MergeData;
END $$
If you CALL merge_and_select() the rMergeDateFields procedure will be run and then you will get the contents of the MergeData table returned to you, in one step... which sounds like what you're wanting.
This is, however, a really bad implementation, because there's no control for concurrent calls to merge_and_select(), so all kinds of things could go wrong if it's run more than once at the same time.
However, depending on what you really need rMergeDateFields() to do, it's possible that you could rewrite rMergeDateFields() to actually perform whatever work you need done and return it directly to the client without using the MergeData table using an unbounded SELECT, as shown above.
Anything you SELECT in a stored procedure without using INTO a variable is returned to the client as a response from the CALL.