How to drop index by passing index name dynamically in my sql? - mysql

tried the below query but not working.
SET #index_name = (SELECT INDEX_NAME
FROM information_schema.statistics
WHERE table_schema = 'myDB'
and table_name = 'test'
and column_name = 'col1');
ALTER TABLE test DROP INDEX #index_name;

The index name cannot be retrieved from the variable in the query. Use dynamic SQL, like
SELECT INDEX_NAME
INTO #index_name
FROM information_schema.statistics
WHERE table_schema = 'myDB'
and table_name = 'test'
and column_name = 'col1'
LIMIT 1;
SET #sql := CONCAT('ALTER TABLE myDB.test DROP INDEX ', #index_name);
PREPARE stmt FROM #sql;
EXECUTE stmt;
DROP PREPARE stmt;

Related

Incorrect parameter count in the call to native function 'JSON_OBJECT'

I'm getting all columns from a table and fetching the result to JSON using the function JSON_OBJECT. But when i execute the stored procedure i'm getting this error.
CREATE DEFINER=`sistema`#`%` PROCEDURE `get_products_as_json`()
BEGIN
SET #fields = (
'SELECT
group_concat(\'\`\', column_name, \'\`\, \', column_name)
FROM
information_schema.columns
WHERE
table_schema = DATABASE()
AND table_name = \'products\'
ORDER BY table_name , ordinal_position'
);
SET #stmt = ('SELECT JSON_OBJECT(?) FROM products LIMIT 10');
PREPARE stmt FROM #stmt;
EXECUTE stmt USING #fields;
DEALLOCATE PREPARE stmt;
END
You cannot use prepared statements in that way.
You have to CONCAT the variable.
I also changed the first SELECT, this works too and is better to read.
DELIMITER $$
CREATE DEFINER=`sistema`#`%` PROCEDURE `get_products_as_json`()
BEGIN
SET #fields = (
SELECT
group_concat('"', column_name, '", ', column_name)
FROM
information_schema.columns
WHERE
table_schema = DATABASE()
AND table_name = 'products'
ORDER BY table_name , ordinal_position
);
SET #stmt = CONCAT('SELECT json_object(',#fields,') FROM products LIMIT 10');
PREPARE stmt FROM #stmt;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END$$
DELIMITER ;
I added also the DELIMITER in case you don_'t use mysql workbench

How to Create View or Table from Prepared Statement (Select Query)

I am trying to create View from the following prepared statement:
CREATE VIEW myview AS -- this line is not working
SELECT CONCAT(GROUP_CONCAT('SELECT ''', COLUMN_NAME,''' MyColumns, SUM(`', COLUMN_NAME,'`) Total FROM mydb.source_table' SEPARATOR '\n UNION ALL \n'),'\nORDER BY Total ASC')
INTO #sql
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = 'mydb'
AND TABLE_NAME = 'source_table'
AND COLUMN_NAME NOT IN ('ID', 'Name');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DROP PREPARE stmt;
I am still confused with handling group_concat syntax.
I just need help on how to create View with the above prepared statement.
UPDATE 1: Stored procedure
As suggested by #nbk, I have to create into 5 stored procedures in single column to be able the data and use it to CREATE TABLE query. Here's the stored procedure version of the above codes.
CREATE DEFINER=`admin`#`%` PROCEDURE `sp_result`()
BEGIN
SELECT CONCAT(GROUP_CONCAT('SELECT ''', COLUMN_NAME,''' MyColumns FROM mydb.source_table' SEPARATOR '\n UNION ALL \n'), '\n LIMIT 0, 1 \n')
INTO #sql
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = 'mydb'
AND TABLE_NAME = 'source_table'
AND COLUMN_NAME NOT IN ('ID', 'Name');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DROP PREPARE stmt;
END
Here's the result of this stored procedure:
+-----------+
| MyColumns |
+-----------+
| Abc |
+-----------+
In order this approach to be useful to me, I want the above result to be the one of the column of my CREATE TABLE query:
Here are my attempts but no luck:
First attempt: Separate Query
CREATE TABLE my_table AS SELECT id, name, mydb.sp_result() FROM source_table; -- Error Code: 1305. FUNCTION project_x.best_vendor1_name does not exist
Second attempt: Inserted at the last part of the stored procedure
CREATE TABLE my_table AS SELECT #sql FROM source_table; -- no effect
Here, I really do not know how CREATE TABLE using the stored procedure returned data.
UPDATE 2: Illustrate Encapsulation
CREATE DEFINER=`root`#`%` PROCEDURE `proc_column_sum`()
BEGIN
DROP TABLE IF EXISTS table2;
SELECT CONCAT('
CREATE TABLE table2 AS (',GROUP_CONCAT('
SELECT ''', COLUMN_NAME,''' MyColumns, SUM(`', COLUMN_NAME,'`) Total
FROM testdb.products '
SEPARATOR '\n UNION ALL \n'), -- runtime syntax error somewhere here
'\n ORDER BY Total ASC)') -- missing closing single quote right after ASC
INTO #sql
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = 'testdb'
AND TABLE_NAME = 'products'
AND COLUMN_NAME NOT IN ('ID', 'Name');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DROP PREPARE stmt;
END
You must put the CREATE TABLE in your prepared statement.
this example uses a temporary table only for demonstration purposes
CREATE DEFINER=`root`#`%` PROCEDURE `proc_column_sum`()
BEGIN
SELECT
CONCAT('CREATE TEMPORARY TABLE IF NOT EXISTS table2 AS (',GROUP_CONCAT('SELECT ''', COLUMN_NAME,''' MyColumns, SUM(`', COLUMN_NAME,'`) Total FROM testdb.products ' SEPARATOR '\n UNION ALL \n'),'\nORDER BY Total ASC)')
INTO #sql
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = 'testdb'
AND TABLE_NAME = 'products'
AND COLUMN_NAME NOT IN ('ID', 'Name');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DROP PREPARE stmt;
END
you call it then
call proc_column_sum();
SELECT * FROM table2
But with this approach you have call every time the procedure to get the newest data.
I can' figure out, what went wrong in your query
CREATE DEFINER=`root`#`%` PROCEDURE `proc_column_sum`()
BEGIN
DROP TABLE IF EXISTS table2;
SELECT CONCAT('
CREATE TABLE IF NOT EXISTS table2 AS (',GROUP_CONCAT('
SELECT ''', COLUMN_NAME,''' MyColumns, SUM(`', COLUMN_NAME,'`) Total
FROM testdb.products '
SEPARATOR '\n UNION ALL \n')
,'\nORDER BY Total ASC)')
INTO #sql
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = 'testdb'
AND TABLE_NAME = 'products'
AND COLUMN_NAME NOT IN ('ID', 'Name');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DROP PREPARE stmt;
END

How to verify if index exists in a table before dropping the index on MySql? [duplicate]

I was wondering if there's a way to check if an index exists before creating it or destroying it on MySQL. It appears that there was a feature request for this a few years back, but I can't find any documentation for a solution. This needs to be done in a PHP app using MDB2.
Here is my 4 liner:
set #exist := (select count(*) from information_schema.statistics where table_name = 'table' and index_name = 'index' and table_schema = database());
set #sqlstmt := if( #exist > 0, 'select ''INFO: Index already exists.''', 'create index i_index on tablename ( columnname )');
PREPARE stmt FROM #sqlstmt;
EXECUTE stmt;
IF EXISTS modifier is not built for DROP INDEX or CREATE INDEX yet. But you can check manually for the existence before creating/dropping an index.
Use this sentence to check whether the index already exists.
SHOW INDEX FROM table_name WHERE KEY_NAME = 'index_name'
If the query returns zero (0) then the index does not exists, then you can create it.
If the query returns a positive number, then the index exists, then you can drop it.
Here is a DROP INDEX IF EXISTS procedure:
DELIMITER $$
DROP PROCEDURE IF EXISTS drop_index_if_exists $$
CREATE PROCEDURE drop_index_if_exists(in theTable varchar(128), in theIndexName varchar(128) )
BEGIN
IF((SELECT COUNT(*) AS index_exists FROM information_schema.statistics WHERE TABLE_SCHEMA = DATABASE() and table_name =
theTable AND index_name = theIndexName) > 0) THEN
SET #s = CONCAT('DROP INDEX ' , theIndexName , ' ON ' , theTable);
PREPARE stmt FROM #s;
EXECUTE stmt;
END IF;
END $$
DELIMITER ;
This code was created based on the procedure from here: Determining if MySQL table index exists before creating
I tweaked answers found here and else where to come up with the following sprocs for dropping & creating indexes. Note that the AddTableIndex sproc can drop the index if need be. They also accept a schema name which was critical for my uses.
DELIMITER //
DROP PROCEDURE IF EXISTS migrate.DropTableIndex //
CREATE PROCEDURE migrate.DropTableIndex
(
in schemaName varchar(128) -- If null use name of current schema;
, in tableName varchar(128) -- If null an exception will be thrown.
, in indexName varchar(128) -- If null an exception will be thrown.
)
BEGIN
SET schemaName = coalesce(schemaName, schema());
IF((SELECT COUNT(*) AS index_exists FROM information_schema.statistics WHERE TABLE_SCHEMA = schemaName and table_name = tableName AND index_name = indexName) > 0) THEN
SET #s = CONCAT('DROP INDEX `' , indexName , '` ON `' , schemaName, '`.`', tableName, '`');
PREPARE stmt FROM #s;
EXECUTE stmt;
END IF;
END //
DROP PROCEDURE IF EXISTS migrate.AddTableIndex//
CREATE PROCEDURE migrate.AddTableIndex
(
IN schemaName varchar(128) -- If null use name of current schema;
, IN tableName varchar(128) -- If null an exception will be thrown.
, IN indexName varchar(128) -- If null an exception will be thrown.
, IN indexDefinition varchar(1024) -- E.g. '(expireTS_ ASC)'
, IN ifPresent ENUM('leaveUnchanged', 'dropAndReplace') -- null=leaveUnchanged.
, OUT outcome tinyint(1) -- 0=unchanged, 1=replaced, 4=added.
)
BEGIN
DECLARE doDrop tinyint(1) DEFAULT NULL;
DECLARE doAdd tinyint(1) DEFAULT NULL;
DECLARE tmpSql varchar(4096) DEFAULT '';
SET schemaName = coalesce(schemaName, schema());
SET ifPresent = coalesce(ifPresent, 'leaveUnchanged');
IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.STATISTICS WHERE table_schema = schemaName AND table_name = tableName AND index_name = indexName) THEN
IF (ifPresent = 'leaveUnchanged') THEN
SET doDrop = 0;
SET doAdd = 0;
SET outcome = 0;
ELSEIF (ifPresent = 'dropAndReplace')
THEN
SET doDrop = 1;
SET doAdd = 1;
SET outcome = 1;
END IF;
ELSE
SET doDrop = 0;
SET doAdd = 1;
SET outcome = 4;
END IF;
IF (doDrop = 1) THEN
SET tmpSql = concat( 'alter table `', schemaName, '`.`', tableName, '` drop index `', indexName, '` ');
SET #sql = tmpSql;
PREPARE tmp_stmt FROM #sql;
EXECUTE tmp_stmt;
DEALLOCATE PREPARE tmp_stmt;
END IF;
IF (doAdd = 1) THEN
SET tmpSql = concat( 'alter table `', schemaName, '`.`', tableName, '` add index `', indexName, '` (', indexDefinition, ')');
SET #sql = tmpSql;
PREPARE tmp_stmt FROM #sql;
EXECUTE tmp_stmt;
DEALLOCATE PREPARE tmp_stmt;
END IF;
END;
//
DELIMITER ;
I have something similar with using SELECT IF() statement in MySQL.
select if (
exists(
select distinct index_name from information_schema.statistics
where table_schema = 'schema_db_name'
and table_name = 'tab_name' and index_name like 'index_1'
)
,'select ''index index_1 exists'' _______;'
,'create index index_1 on tab_name(column_name_names)') into #a;
PREPARE stmt1 FROM #a;
EXECUTE stmt1;
DEALLOCATE PREPARE stmt1;
The advantage of using if() statement is that, it doesn’t need a stored procedures.
I think this will helpful to you drop your existing index.
DELIMITER //
CREATE PROCEDURE dropIndexing
()
BEGIN
IF EXISTS(
SELECT * FROM information_schema.statistics
WHERE TABLE_SCHEMA = DATABASE()
AND `table_name`='mytable'
AND `index_name` = 'myindex'
)
THEN
ALTER TABLE `mytable` DROP INDEX `myindex`;
END IF;
END //
DELIMITER ;
CALL dropIndexing();
DROP PROCEDURE dropIndexing;
MySQL Workbench version 6.3 (MySql fork MariaDb)
DROP INDEX IF EXISTS FK_customer__client_school__school_id ON dbname.tablename;
I was having problems with some of the solutions presented here. This is what I came up with:
DELIMITER $$
DROP PROCEDURE IF EXISTS myschema.create_index_if_not_exists $$
CREATE PROCEDURE myschema.create_index_if_not_exists(in p_tableName VARCHAR(128), in p_indexName VARCHAR(128), in p_columnName VARCHAR(128) )
BEGIN
PREPARE stmt FROM 'SELECT #indexCount := COUNT(1) from information_schema.statistics WHERE `table_name` = ? AND `index_name` = ?';
SET #table_name = p_tableName;
SET #index_name = p_indexName;
EXECUTE stmt USING #table_name, #index_name;
DEALLOCATE PREPARE stmt;
-- select #indexCount;
IF( #indexCount = 0 ) THEN
SELECT 'Creating index';
SET #createIndexStmt = CONCAT('CREATE INDEX ', p_indexName, ' ON ', p_tableName, ' ( ', p_columnName ,')');
PREPARE stmt FROM #createIndexStmt;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END IF;
END $$
DELIMITER ;
Use it as follows:
call myschema.create_index_if_not_exists('MyTable','end_time_index','end_time');
This was tested on MAC OS X 10.8.2 with MySQL 5.5.24 and on Windows 7 with MySQL 5.5.21
Here is a workaround for the DROP INDEX IF EXISTS, that is missing in MySQL and MariaDB versions before v10.1.4. You can also use it for every other statement you want, that should be depend on the existence of an INDEX (e.g. for SELECT "info: index exists." like in the example below).
-- DROP INDEX IF EXISTS
SELECT
COUNT(*)
INTO
#INDEX_my_index_ON_TABLE_my_table_EXISTS
FROM
`information_schema`.`statistics`
WHERE
`table_schema` = 'my_database'
AND `index_name` = 'my_index'
AND `table_name` = 'my_table'
;
SET #statement := IF(
#INDEX_my_index_ON_TABLE_my_table_EXISTS > 0,
-- 'SELECT "info: index exists."',
'DROP INDEX `my_index` ON `my_table`',
'SELECT "info: index does not exist."'
);
PREPARE statement FROM #statement;
EXECUTE statement;

Is there a way to test for null on all columns in a wildcard select?

PSEUDO:
select * from foo where [every column is not null]
Is there a way to do this without specifying the actual column names?
A possible solution that I can think of involves using dynamic-SQL
SELECT GROUP_CONCAT(column_name SEPARATOR ' IS NOT NULL AND ')
INTO #sql
FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_schema = SCHEMA()
AND table_name = 'foo'
GROUP BY table_name;
SET #sql = CONCAT('SELECT * FROM foo WHERE ', #sql, ' IS NOT NULL');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
Here is SQLFiddle demo
Obviously it can be wrapped into a stored procedure with a parameter for a table name
DELIMITER $$
CREATE PROCEDURE sp_select_all_not_null(IN tbl_name VARCHAR(64))
BEGIN
SELECT GROUP_CONCAT(column_name SEPARATOR ' IS NOT NULL AND ')
INTO #sql
FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_schema = SCHEMA()
AND table_name = tbl_name
GROUP BY table_name;
SET #sql = CONCAT('SELECT * FROM ', tbl_name, ' WHERE ', #sql, ' IS NOT NULL');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END
DELIMITER ;
And then use it
CALL sp_select_all_not_null('foo');
Here is SQLFiddle demo for that

MySQL Dropping Tables

What syntax for MySQL would I use to drop multiple tables that have a similar pattern to them? Something like:
DROP TABLES FROM `Database1` LIKE "SubTable*"
Since DROP TABLE was supported by prepared statements, it can be done in this way -
SET #tables = NULL;
SELECT GROUP_CONCAT(table_schema, '.', table_name) INTO #tables FROM information_schema.tables
WHERE table_schema = 'Database1' AND table_name LIKE 'SubTable%';
SET #tables = CONCAT('DROP TABLE ', #tables);
PREPARE stmt1 FROM #tables;
EXECUTE stmt1;
DEALLOCATE PREPARE stmt1;
As noted on this question, the responses given here (Angelin and Devart) won't work in all circumstances without first increasing the limit of group_concat, as per below:
SET group_concat_max_len = 1024 * 1024 * 10;
No. But you can select tables names from information_schema database:
select table_name
from information_schema.tables
where table_schema = 'Database1'
and table_name like 'SubTable%'
And after that iterate the table names in result set and drop them
mysql> SELECT CONCAT( "DROP TABLE ", GROUP_CONCAT(TABLE_NAME) ) AS
stmt
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = "your_db_name" AND TABLE_NAME LIKE "ur condition"
into outfile '/tmp/a.txt';
mysql> source /tmp/a.txt;