Using Dynamic MySQL to create a new table - mysql

I want to change this query:
CREATE TABLE diablo.diablo_sales2 LIKE diablo.diablo_sales;
to a dynamic one like this:
set #old = 'diablo_sales';
set #new = 'diablo_sales2 ';
set #schema = 'diablo';
set #query = 'create table #schema.#new like #schema.#old';
Is this even possible in MySQL? How can I execute #query?
EDIT: below is the whole query I'm trying to make dynamic
-- create same table structure - blank table
CREATE TABLE diablo.diablo_sales2 LIKE diablo.diablo_sales;
-- add the new column(s)
ALTER TABLE diablo.diablo_sales2
add column new_column decimal(10);
-- insert the old data into new table - new column will remain blank
INSERT INTO diablo.diablo_sales2
(
column1,
column2
)
SELECT * FROM diablo.diablo_sales;
-- rename the new table to its original name. Drop the old table.
RENAME table diablo_sales TO `old`, diablo_sales2 TO diablo_sales;
DROP TABLE old;

You can use the SQL Syntax for Prepared Statements:
SET #sql := CONCAT('
CREATE TABLE `',REPLACE(#schema,'`','``'),'`.`',REPLACE(#new,'`','``'),'`
LIKE `',REPLACE(#schema,'`','``'),'`.`',REPLACE(#old,'`','``'),'`
');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
I have taken the liberty of quoting the identifiers and calling REPLACE() to escape any quotes contained therein, in order to protect against SQL injection.

Related

MySQL Procedure to CREATE multiple tables is not working (WHILE loop dynamic SQL)

I have added a stored procedure to create multiple tables in dynamic SQL using WHILE loop in MySQL Workbench. The query creates last table only, instead of all. I have checked with drop table to delete the if table exists. But it still show already exists. Here is the query.
CREATE DEFINER=`root`#`localhost` PROCEDURE `weeklyLooper`(IN weeklycount INT)
BEGIN
SET #count = 0;
SET #weeklylooper = weeklycount;
SET #dumpclear = CONCAT('week' , #weeklylooper);
WHILE #count <= #weeklylooper DO
set #count = #count+1;
SET #weeklyname = CONCAT('week' , #count);
SET #weekly = CONCAT('total_' , #weeklyname, '_deposits');
SET #dropquery = CONCAT('DROP TABLE IF EXISTS `', #weeklyname, '`');
PREPARE droptablequery FROM #dropquery;
EXECUTE droptablequery;
DEALLOCATE PREPARE droptablequery;
SET #selectquery = CONCAT('CREATE temporary TABLE ', #weeklyname ,' AS SELECT sum(deposits) As ', #weekly,' FROM base0');
PREPARE selecttablequery FROM #selectquery;
EXECUTE selecttablequery;
DEALLOCATE PREPARE selecttablequery;
END WHILE;
END
Please help me to complete this.
You are creating temporary tables - temporary tables only exist for the extent of the session - since every exec is in a unique session AND DIFFERS from the session you are running the procedure in the temporary tables are never available to the session in which you are running the procedure...
or as the manual says 'You can use the TEMPORARY keyword when creating a table. A TEMPORARY table is visible only within the current session, and is dropped automatically when the session is closed.' https://dev.mysql.com/doc/refman/8.0/en/create-temporary-table.html
Consider creating permanent tables and deleting them when you are done.

Insert Values on Input Variable Array

I have the following input of a list of clients I get from an external application that comes into a variable in a MySQL stored procedure such as this:
"2841,2212,1231,xxxx,...,1221"
...called input_clients
I want to take this list and insert it all in a temporary table with the field client_id.
I am wondering if someone can either point me to an existing script or show me how I can format this in a stored procedure that input so it will work as
INSERT INTO select_Clients(client_id) VALUES (input_client1), (input_client2)
because currently input_client stores all those clients in 1 string.
You can create a prepared statement inside the procedure as string and then execute it:
SET #input = '2841,2212,1231,1221';
DROP TEMPORARY TABLE IF EXISTS select_Clients;
CREATE TEMPORARY TABLE select_Clients(client_id INT);
SET #sql = CONCAT('INSERT INTO select_Clients(client_id) VALUES (', REPLACE(#input, ',', '),('), ')');
PREPARE stmt FROM #sql;
EXECUTE stmt;
http://rextester.com/FPDW88636

How to convert an SQL select query into a formatted HTML table within a MySQL function

I'm looking for a way to generate valid HTML code within MySQL (without PHP) by converting any query output into an HTML table.
Here's my progress so far and evidently, I'm stuck. I hope I can get some help, thanks.
1. "dynSQL" - A procedure to take any Select query and create a named table out of it
Since MySQL doesn't allow dynamic queries in functions, I'm calling a procedure that creates a named table, tmp. I can't use a temporary table because info about temporary tables is not available in information_schema (in mysql 5.6)
CREATE DEFINER=`root`#`%` PROCEDURE `dynSQL`(SQL_QUERY TEXT)
BEGIN
set #SQLQ := 'Drop table if exists tmp;';
PREPARE stmt from #SQLQ;
Execute stmt;
SET #SQLQ := concat('create table tmp as ',SQL_QUERY);
PREPARE stmt from #SQLQ;
Execute stmt;
-- I'm adding a auto increment ID column to be able to loop through the rows later
SET #SQLQ := "ALTER TABLE tmp add column CustColHTML_ID INT NOT NULL AUTO_INCREMENT FIRST, ADD primary KEY Id(CustColHTML_ID)";
PREPARE stmt from #SQLQ;
Execute stmt;
DEALLOCATE PREPARE stmt;
END
2. "MakeHTML" - Function to read from the table tmp and return a formatted HTML table
CREATE DEFINER=`root`#`%` FUNCTION `MakeHTML`() RETURNS text CHARSET utf8
DETERMINISTIC
BEGIN
DECLARE HTML text default "<TABLE><TR>";
DECLARE rowCount int default 0;
DECLARE i int default 0;
select concat('<TR>',group_concat('<TD>',column_name,'</TD>' separator ''),'</TR>') into html from information_Schema.`columns` where table_name='tmp';
Select max(CustColHTML_ID) into rowCount from `tmp`; -- Set the row counter
WHILE i<=rowCount DO
-- What do I do here? How do I loop through the columns of table tmp?
set i:=i+1;
END WHILE;
RETURN HTML;
END
As you can see, I'm stuck at looping through the unknown and dynamic columns of table tmp. I read about how a cursor can be used here, but all the examples I saw make use of known columns and assign those into named variables. However, since the query itself is dynamic, I wouldn't know the names of the columns.
I'd really appreciate your time and assistance, thanks!
p.s. I've posted this as a new question because my earlier question was marked as closed as being too broad. I subsequently edited my question but it was still showing as Closed. I've therefore deleted the older question and replaced it with this one.
With a sample table as such:
CREATE TABLE tmp (ID INT, Col1 INT, Col2 INT);
The SQL you would need to generate your HTML is:
SELECT CONCAT('<table>', GROUP_CONCAT(CONCAT('<tr><td>',ID,'</td><td>',Col1,'</td><td>',Col2,'</td><tr>')), '</table>')
FROM tmp;
You can generate this using the INFORMATION_SCHEMA:
SELECT CONCAT
(
'SELECT CONCAT(''<table>'', GROUP_CONCAT(CONCAT(''<tr>'', ',
GROUP_CONCAT(CONCAT('''<td>'',', COLUMN_NAME, ',''</td>''')),
', ''</tr>'')), ''</table>'') FROM tmp'
)
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'tmp';
It is then just a case of executing this:
SET #SQL = (
SELECT CONCAT
(
'SELECT CONCAT(''<table>'', GROUP_CONCAT(CONCAT(''<tr>'', ',
GROUP_CONCAT(CONCAT('''<td>'',', COLUMN_NAME, ',''</td>''')),
', ''</tr>'')), ''</table>'') FROM tmp'
)
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'tmp'
);
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
Example on SQL Fiddle
ADDENDEUM
Forgot to include table headers:
SET #SQL = (
SELECT CONCAT
(
'SELECT CONCAT(''<table><tr>'',',
GROUP_CONCAT(CONCAT('''<th>'',''', COLUMN_NAME, ''',''</th>''')),
', ''</tr>'', GROUP_CONCAT(CONCAT(''<tr>'', ',
GROUP_CONCAT(CONCAT('''<td>'',', COLUMN_NAME, ',''</td>''')),
', ''</tr>'')), ''</table>'') FROM tmp'
)
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'tmp'
);
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
Example on SQL Fiddle

Changing Multiple DB Fields to Lower Case

With phpMyAdmin, I can use the following SQL to change all values in the table.field mytable.Site to lower case...
UPDATE my_table SET Site=LOWER(Site)
I have a zillion tables that have this same field, and I'd like to change all of them to lower case. Is there a SQL command that will do that - change EVERY field named Site in every table to lower case (preferably without having to list every table that has that field)?
Not EXACTLY what you want,but pretty close.Tested on my machine.
First create a procedure
delimiter //
CREATE PROCEDURE test(IN tbl CHAR(64))
BEGIN
SET #s = CONCAT('UPDATE ',tbl,' SET Site=LOWER(Site)' );
PREPARE stmt FROM #s;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END
//
delimiter ;
And for finding tables with a certain column name:
SELECT TABLE_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE COLUMN_NAME IN ('Site')
AND TABLE_SCHEMA='YourDB';
For calling the procedure
CALL test('tableName')

Key commands for creating temporary tables

I am creating temporary tables in stored procedures. Wanted to know what commands to include in procedure to avoid conflicts?
i usually use below syntax
CREATE TEMPORARY TABLE IF NOT EXISTS temp_shipmentcount
and use
drop command at end.
should i add drop command at beginning of procedure also?
Temporary tables are connection scoped. They only exist until the connection is closed.
As per documentation on Temporary tables
You can use the TEMPORARY keyword when creating a table. A TEMPORARY table is visible only to the current connection, and is dropped automatically when the connection is closed. This means that two different connections can use the same temporary table name without conflicting with each other or with an existing non-TEMPORARY table of the same name...
If a connection is not closed but shared among users, then you have to drop it and re-create. But dropping a database object using a shared connection will result issues.
It would be a better option to use temporary tables with runtime generated names within a stored procedure. This is safe on using shared connection objects too.
Exampe:
set #temp_table_name := concat( 'temp_table_', ( CURRENT_TIMESTAMP + 0 ) );
set #sql := concat( 'create temporary table ', #temp_table_name );
set #select_stmt := concat( 'select this', blah, blah );
set #sql := concat( #sql, ' as ' , #select_stmt );
prepare stmt from #sql;
execute stmt;
drop prepare stmt;
-- perform opearations on temp table
--
-- in between here
--
-- and then drop it before leaving
set #drop_temp := concat( 'drop temporary table ', #temp_table_name );
prepare stmt from #drop_temp;
execute stmt;
drop prepare stmt;