mysql temporary table in subquery - mysql

I'm trying to use temp table in subquery (stored procedure), but it returns empty result set...
CREATE DEFINER=`root`#`localhost` PROCEDURE `get_profile_with_templates`(IN _username NVARCHAR(50), IN _template NVARCHAR(50))
BEGIN
SELECT id INTO #template FROM profile_template WHERE name=_template LIMIT 1;
SELECT * FROM profile WHERE username=_username AND template=#template LIMIT 1;
CREATE TEMPORARY TABLE IF NOT EXISTS sections SELECT * FROM profile_template_section WHERE template=#template;
**CREATE TEMPORARY TABLE IF NOT EXISTS components SELECT * FROM component_template WHERE section IN (SELECT id FROM sections);**
SELECT * FROM sections;
SELECT * FROM components;
SELECT * FROM component_template_option WHERE component_template IN (SELECT id FROM components);
END
the query between the **'s is the one returns empty...
if I run the same query on the real table, It returns values...
CREATE DEFINER=`root`#`localhost` PROCEDURE `get_profile_with_templates`(IN _username NVARCHAR(50), IN _template NVARCHAR(50))
BEGIN
DROP TEMPORARY TABLE IF EXISTS sections;
DROP TEMPORARY TABLE IF EXISTS components;
SELECT id INTO #template FROM profile_template WHERE name=_template LIMIT 1;
SELECT * FROM profile WHERE username=_username AND template=#template LIMIT 1;
CREATE TEMPORARY TABLE IF NOT EXISTS sections SELECT * FROM profile_template_section WHERE template=#template;
CREATE TEMPORARY TABLE IF NOT EXISTS components SELECT * FROM component_template WHERE section IN (SELECT id FROM sections);
SELECT * FROM sections;
SELECT * FROM components;
SELECT * FROM component_template_option WHERE component_template IN (SELECT id FROM components);
DROP TEMPORARY TABLE IF EXISTS sections;
DROP TEMPORARY TABLE IF EXISTS components;
END

When using CREATE ... SELECT statements, the SELECT portion will not populate the table if it already exists.
If creating temporary tables in a stored procedure that will not be used outside of the procedure, it is best to use DROP TEMPORARY TABLE IF EXISTS statements at the start and end of the procedure. The ending ones are so the procedure cleans up after itself; the starting ones ensure temporary tables left over from previous executions (that errored/failed before dropping them) do not interfere with current executions. You could also wrap the main body of the procedure in a TRY, and have the drops outside of the TRY, to ensure the drops occur, but that is a bit more advanced.
When using session/user/# variables, keep in mind they are global for the database connection and can carry over values; when possible use locally DECLAREd variables (whose scope does not go beyond the procedure). Bonus: Also, try to make sure the names of such variables, and procedure parameters, are not ambiguous with field names of the tables used in the procedure; it can cause very hard to diagnose issues.

Related

How to select content from a table into a new table in SQL stored procedures?

I was trying to write a procedure and needed to copy output_1 table into a new one.
This procedure :
BEGIN
SELECT * INTO newtable FROM output_1;
END
returns the following error :Undeclared variable: newtable
I thought it would create a new table and all its columns automatically.
How do I SELECT multiple columns of a table INTO a new table using a stored procedure?
EDIT :
In stored procedures, when you want to use a table to store data temporarily, you should consider using temporary tables.
Typically, if you try to store a table in a variable, you will get a multiple rows error ; in this case, temporary tables can replace variables.
CREATE TEMPORARY TABLE new_table AS SELECT * FROM output_1;
You cannot select into a table. You possibly intended
create table newtable as select * from output_1;
https://dev.mysql.com/doc/refman/8.0/en/create-table-select.html

mySQL creating multiple temporary tables

I have a Stored Procedure in mySQL that takes a subset of data from a table and performs some analysis on that subset within a temp table. Here is my code:
CREATE PROCEDURE GetPortfolioStats
(
InIdx_i INT,
InStart_i INT,
InEnd_i INT
)
BEGIN
DECLARE myLimit INT;
DECLARE myOffset INT;
SET myLimit = InEnd_i - InStart_i + 1;
SET myOffset = InStart_i - 1;
CREATE TEMPORARY TABLE IF NOT EXISTS myTmpTable AS (SELECT * FROM Leases WHERE Portfolio_i = InIdx_i ORDER BY Index_i LIMIT myLimit OFFSET myOffset);
SET #Additive_i := (SELECT COUNT(Index_i) FROM myTmpTable WHERE ReviewType_vc = 'Additive');
DROP TABLE myTmpTable;
SELECT #Additive_i;
END; GO
This works fine. However, the problem I have is that this is a multi-threaded application and when multiple threads are calling this stored proc, they start sharing the same temp table, which messes up the Stats I'm trying to compile.
Is there a way to either apply a unique table name to each call of the stored proc or limit the scope of the temp table to just that instance of the stored proc?
To answer the specific question: the easiest solution would be to use a different database connection per thread because temporary tables are session (connection) specific:
You can use the TEMPORARY keyword when creating a table. A TEMPORARY table is visible only to the current session, and is dropped automatically when the session is closed. This means that two different sessions can use the same temporary table name without conflicting with each other or with an existing non-TEMPORARY table of the same name.
However, after checking out the actual code, I would suggest not to use a temporary table at all, use a single query with a subquery:
SELECT COUNT(Index_i)
FROM
(SELECT Index_i, ReviewType_vc
FROM Leases
WHERE Portfolio_i = InIdx_i
ORDER BY Index_i
LIMIT myLimit OFFSET myOffset) t
WHERE ReviewType_vc = 'Additive'

MySQL Temp table Insert

I'm using MySQL and trying to create a temp table. I will be doing a 2 while loop statements in PHP to populate the temp table. Firstly though I can't seem to get the Insert into temp table to work. I've tried many different versions of this, some using '#' for the table and various things (are there differences in SQL server and MySQL commands?). Here's my last attempt (P.S the Select statement works fine on its own).
CREATE TEMPORARY TABLE temp
(
aID varchar(15) NOT NULL,
bID varchar(15) NOT NULL
)
INSERT INTO temp
SELECT aID, bID
FROM tags
WHERE placeID = "abc" AND tagID = "def";
Help appreciated!
Also, just a general Q...this query will have to be run many times. Will using temp tables be OK or cause the server issues?
working on what Code-Monk wrote, consider the following:
drop procedure if exists uspK;
DELIMITER $$
create procedure uspK ()
BEGIN
drop temporary table if exists temp; -- could be some other random structure residue
create temporary table temp
SELECT aID, bID
FROM tags
WHERE placeID = "abc" AND tagID = "def";
-- use the temp table somehow
-- ...
-- ...
-- ...
drop temporary table temp; -- otherwise it survives the stored proc call
END
$$ -- signify end of block
DELIMITER ; -- reset to default delimiter
Test Stored Procedure
call uspK(); -- test it, no warnings on edge conditions
What not to do
One would not find much luck with the following. If you think so, run it a few times;
drop procedure if exists uspK;
DELIMITER $$
create procedure uspK ()
BEGIN
-- drop temporary table if exists temp;
create temporary table if not exists temp
SELECT aID, bID
FROM tags
WHERE placeID = "abc" AND tagID = "def";
-- use the temp table somehow
-- ...
-- ...
-- ...
-- drop temporary table temp; -- otherwise it survives the stored proc call
END
$$ -- signify end of block
DELIMITER ; -- reset to default delimiter
because create temporary table if not exists temp is flakey
General Comments
One should not embark into writing stored procs until somewhat fluent on the simple topic of DELIMITERS. Wrote about them in a section here called Delimiters. Just hoping to head you off from unnecessary wasted time on such a simple thing, than can waste a lot of debugging time.
Also, here in your question, as well as in that reference, keep in mind that the creation of tables is DDL that can have a large percentage of the overall profiling (performance). It slows down a proc versus using a pre-existing table. One might think the call is instantaneous, but it is not. As such, for performance, using a pre-existing table with ones results put into their own segmented rowId is much faster than enduring DDL overhead.
You can create temporary table and insert select statemet in following way:
create temporary table temp
SELECT aID, bID
FROM tags
WHERE placeID = "abc" AND tagID = "def";
To drop the temporary table before creating it again. put following statement before creating temporary table:
drop temporary table if exists temp;
Note: It will be good if you can put all this code in stored procedure. and call it to create temporary table.

Stored Procedure with a IN statement (mysql)

I have a query like
Select id,name,... FROM table WHERE id IN (?)
The query is actually more complicated with joins and another (?) with the same ids. I've been told to put it on a stored procedure to make it easier to manage and safer, but mysql doesn't support arrays, so I'm not sure what is the best way to do it, considering that I don't know how many id I will have to pass. I have seen people passing a string. Is it the only way?
You can use temporary tables. Though this answer is not highly voted so I suppose that using a string parameter is the prefered way (17 votes vs 2 votes) (see the link). The answer with temporary table is taken from another question: Pass array to MySQL stored routine
Use a join with a temporary table. You don't need to pass temporary
tables to functions, they are global.
create temporary table ids( id int ) ;
insert into ids values (1),(2),(3) ;
delimiter //
drop procedure if exists tsel //
create procedure tsel() -- uses temporary table named ids. no params
READS SQL DATA
BEGIN
-- use the temporary table `ids` in the SELECT statement or
-- whatever query you have
select * from Users INNER JOIN ids on userId=ids.id ;
END //
DELIMITER ;
CALL tsel() ; -- call the procedure

Creating temporary tables in MySQL Stored Procedure

The following procedure gives me an error when I invoke it using the CALL statement:
CREATE DEFINER=`user`#`localhost` PROCEDURE `emp_performance`(id VARCHAR(10))
BEGIN
DROP TEMPORARY TABLE IF EXISTS performance;
CREATE TEMPORARY TABLE performance AS
SELECT time_in, time_out, day FROM attendance WHERE employee_id = id;
END
The error says "Unknown table 'performance' ".
This is my first time actually using stored procedures and I got my sources from Google. I just cant figure out what I am doing wrong.
I've tidied it up a little for you and added example code. I always keep my parameter names the same as the fields they represent but prefix with p_ which prevents issues. I do the same with variables declared in the sproc body but prefix with v_.
You can find another one of my examples here:
Generating Depth based tree from Hierarchical Data in MySQL (no CTEs)
drop procedure if exists emp_performance;
delimiter #
create procedure emp_performance
(
in p_employee_id varchar(10)
)
begin
declare v_counter int unsigned default 0;
create temporary table tmp engine=memory select time_in, time_out
from attendance where employee_id = p_employee_id;
-- do stuff with tmp...
select count(*) into v_counter from tmp;
-- output and cleanup
select * from tmp order by time_in;
drop temporary table if exists tmp;
end#
delimiter ;
call emp_performance('E123456789');
By default MySQL config variable sql_notes is set to 1.
That means that
DROP TEMPORARY TABLE IF EXISTS performance;
increments warning_count by one and you get a warning when a stored procedure finishes.
You can set sql_notes variable to 0 in my.cnf or rewrite stored procedure like that:
CREATE DEFINER=`user`#`localhost` PROCEDURE `emp_performance`(id VARCHAR(10))
BEGIN
SET ##session.sql_notes = 0;
DROP TEMPORARY TABLE IF EXISTS performance;
CREATE TEMPORARY TABLE performance AS
SELECT time_in, time_out, day FROM attendance WHERE employee_id = id;
SET ##session.sql_notes = 1;
END