Im having a database which is over 60k tables and i want to delete all the tables that have 1 or 2 rows.
You can use the below code in SQL Server 2012. It will delete all the tables which is having row_count less than 3.
USE [YourDB]
GO
DECLARE #Max int, #Count int,#Table_Name Varchar(20)
SET #Max =0
IF OBJECT_ID('tempdb..#temp') IS NOT NULL
DROP TABLE #temp
CREATE TABLE #temp
(
table_name sysname ,
row_count INT,
reserved_size VARCHAR(50),
data_size VARCHAR(50),
index_size VARCHAR(50),
unused_size VARCHAR(50)
)
IF OBJECT_ID('tempdb..#temp1') IS NOT NULL
DROP TABLE #temp1
CREATE TABLE #temp1
(
ID int IDENTITY(1,1),
table_name sysname ,
row_count INT
)
SET NOCOUNT ON
INSERT #temp
EXEC sp_msforeachtable 'sp_spaceused ''?'''
INSERT INTO #temp1
SELECT a.table_name,
a.row_count
FROM #temp a
INNER JOIN information_schema.columns b
ON a.table_name collate database_default
= b.table_name collate database_default
GROUP BY a.table_name, a.row_count
HAVING a.row_count <3
SET #Count =(SELECT COUNT(*) FROM #temp1)
WHILE #Count > #Max
BEGIN
SET #Max = #Max +1
SET #Table_Name = (SELECT table_name FROM #temp1 WHERE ID = #Max)
EXEC('DROP TABLE ' +#Table_Name)
END
Use a MySQL-GUI, order by number of rows and drop all tables with 1-2 rows. it is as easy as deleting files in a windows folder. this
would take ~10 seconds + sort and drop time
or
Select table names of tables with 1-2 rows from information_schemas, load into an excel file and build your drop statements. takes around 2-5 minutes + drop time
or
Build a stored procedure that uses a Cursor to parse all the relevant table names into variables of your drop statement (like Hansa mentioned). this makes sense if you want to repeat your process from time to time. takes around 1-12 hours for beginners (depending on knowledge level) + drop time
Since logging in on SO probably took more time than solution 1 would,
i would recommend that solution.
In case you want to spend more time , the following query will show all table names for tables with 1-2 rows:
SELECT table_schema, table_name From information_schema.tables
WHERE table_schema='your_schema' # use your table_schema here
AND table_rows BETWEEN 1 and 2 ;
I would do it within some application side logic, using a programming language of your choice (which offers a mysql API).
Get all table names, described here, grouping them by table names
e.g. this could look something like:
SELECT COUNT(table_rows), table_name
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = '{your_db}'
GROUP BY table_name;
(this is not tested, but to give you a basic idea...)
Execute a delete statement for the tables with rowcount 2 or lower. Should be an easy task as soon as you got the results in your programming language (btw SQL statement to delete them is "DROP TABLE")
Note: I think it should be also possible using a SQL cursor, but as I said I would prefer the above solution.
You can try this.
First take all the table names from the database.
After getting all the table names put them in a array and execute a foreach loop that checks the num of rows for each table, something like this
$tables = array();
foreach ($tables as $table_name){
$query = "select * from '$table_name'";
$result = mysqli_query($dbCon, $query);
$num_rows = mysql_num_rows($result);
if($num_rows < 3){
$delete = "drop table $table_name";
$res_del = mysqli_query($dbCon, $delete);
echo $table_name." Deleted";
}
}
You probably cant do this with 1 SQL Statement unless you are using stored procedures (see below).
You will need to select all tables in MySQL with a programming language (e.g. Java with JDBC) using the following statement:
select TABLE_NAME from INFORMATION_SCHEMA.TABLES where TABLE_ROWS <= 2 AND TABLE_ROWS >= 1
Then you can use the results in the programming languge to issue drop Statements for each result record in a loop:
drop table <tablename>
For doing this with a stored procedure (i.e. without a programming language)
see the third comment on this page: MySQL Reference Drop Table.
Of course you will need to adapt this to your needs because this example does not select tables by their row numbers but by their names.
Related
I'm creating a function in mySQL that will update table metrics each time the any table has something inserted or deleted from it. So I've got my Table_metrics table, with elements table_name and row_count:
CREATE TABLE Table_metrics (
table_name VARCHAR(64),
row_count INTEGER DEFAULT 0 );
So any time something gets added to any of my tables (other than this one) in the database the matching row gets updated with the number of rows in that table.
To do this I've tried making a stored procedure:
CREATE PROCEDURE table_update_metric(IN tablename VARCHAR(64))
UPDATE Table_metrics
SET row_count=(SELECT COUNT(*) FROM tablename)
WHERE table_name = tablename;
This produces an error when I call the procedure call table_update_metric('Owners'); (Owners being a table in my database)
table DB.tablename doesn't exist
I've done a bit of digging into stored procedures, trying to figure out how they would work. I assume the issue is coming from the line `SELECT COUNT(*) FROM tablename), so I tried having a stored statement in the procedure:
CREATE PROCEDURE table_update_metric(IN TABLENAME VARCHAR(64))
SET #s = CONCAT('SELECT COUNT(*) FROM ', tablename)
UPDATE Table_metrics
SET row_count=EXECUTE #s
WHERE table_name = tablename;
I'm not really sure how to properly do a stored statement as I'm still relatively new to mySQL, but I believe that it's the way to go.
Can anyone offer any insight into this problem?
What you are trying to do is already provided in Mysql. Information Schema Tables stores this information for you :)
SELECT TABLE_NAME, TABLE_ROWS)
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = '{your_db}';
From what Somonare said, I created a table in my database that uses that information:
CREATE TABLE Table_metrics
SELECT TABLE_NAME, TABLE_ROWS FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = 'Sensors';
And this table will be updated with a trigger each time the tables in Sensors are updated.
In my project I have two code paths that interact with MySQL during first time setup. The first step is the database structure creation, in here, a user has the ability to pick and choose the features they want - and some tables may not end up being created in the database depending on what the user selects.
In the second part, I need to preload the tables that did get created with some basic data - how could I go about inserting rows into these tables, only if the table exists?
I know of IF NOT EXISTS but as far as I know, that only works with creating tables, I am trying to do something like this
INSERT INTO table_a ( `key`, `value` ) VALUES ( "", "" ) IF EXISTS table_a;
This is loaded through a file that contains a lot of entries, so letting it throw an error when the table does not exist is not an option.
IF (SELECT count(*)FROM information_schema.tables WHERE table_schema ='databasename'AND table_name ='tablename') > 0
THEN
INSERT statement
END IF
Use information schema to check existence if table
If you know that a particular table does exist with at least 1 record (or you can create a dummy table with just a single record) then you can do a conditional insert this way without a stored procedure.
INSERT INTO table_a (`key`, `value`)
SELECT "", "" FROM known_table
WHERE EXISTS (SELECT *
FROM information_schema.TABLES
WHERE (TABLE_SCHEMA = 'your_db_name') AND (TABLE_NAME = 'table_a')) LIMIT 1;
I've been googling to find an answer but can't find anything. I have a cursor statement that pulls the name of the tables that are present in the database.
THe goal is:
a stored procedure with 2 parameters, database1 and database2
comparing both databases and outputting the difference.
database names are tab/space delimited
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE db_tables VARCHAR(256);
DECLARE cursor1 CURSOR FOR
SELECT TABLE_NAME, TABLE_SCHEMA
FROM information_schema.tables
WHERE TABLE_SCHEMA = db1
AND TABLE_TYPE = 'BASE TABLE';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN cursor1;
FETCH cursor1 into db_tables;
WHILE done = FALSE DO
SET query1 = SELECT * FROM db1 WHERE table1 IN(table_name);
END WHILE;
CLOSE cursor1;
END
This uses the INFORMATION_SCHEMA.TABLES information
The Schema
create database db1;
create database db2;
create table db1.s1 (id int);
create table db1.s2 (id int);
create table db1.s3 (id int);
create table db2.s2 (id int);
create table db2.s3 (id int);
create table db2.s4 (id int);
The Query
select t1.table_name, 2 as 'not in this one'
from INFORMATION_SCHEMA.TABLES t1
where t1.table_schema='db1'
and not exists (select * from INFORMATION_SCHEMA.TABLES t2 where t2.table_schema='db2' and t2.table_name=t1.table_name)
union
select t1.table_name, 1 as 'not in this one'
from INFORMATION_SCHEMA.TABLES t1
where t1.table_schema='db2'
and not exists (select * from INFORMATION_SCHEMA.TABLES t2 where t2.table_schema='db1' and t2.table_name=t1.table_name)
The Results
+------------+-----------------+
| table_name | not in this one |
+------------+-----------------+
| s1 | 2 |
| s4 | 1 |
+------------+-----------------+
This means that table s1 is in database db1, but not in db2, and that table s4 is in the database db2, but not in db1.
Stored Proc
delimiter $$
create procedure showDBDiffInTableNames
( x1 varchar(40),x2 varchar(40) )
BEGIN
--
-- passed parameters, x1 is a string containing the name of a database
-- x2 is a string containing the name of another database
--
select t1.table_name, 2 as 'not in this one'
from INFORMATION_SCHEMA.TABLES t1
where t1.table_schema=x1
and not exists (select * from INFORMATION_SCHEMA.TABLES t2 where t2.table_schema=x2 and t2.table_name=t1.table_name)
union
select t1.table_name, 1 as 'not in this one'
from INFORMATION_SCHEMA.TABLES t1
where t1.table_schema=x2
and not exists (select * from INFORMATION_SCHEMA.TABLES t2 where t2.table_schema=x1 and t2.table_name=t1.table_name);
END
$$
DELIMITER ;
Test it:
call showDBDiffInTableNames('x1','x2');
same results
t1 and t2 are just table aliases. See the manual page here. From the manual page:
The following list describes general factors to take into account when
writing joins.
A table reference can be aliased using tbl_name AS alias_name or
tbl_name alias_name:
....
I almost never write a query without an alias if, knowing ahead of time, I am going after two or more tables. It cuts down on the typing. They are especially common in self-joins (to the same table). You need a way to differentiate which one you are dealing with to remove Ambiguous errors from queries. So that is why that alias is in there. Plus, you will note that the table is gone after twice.
There are two ways you can write it, as seen in the pink/peach block above.
hIs there any way to update all the columns of a mysql table for a particular record in one go to a particular value.
For e.g. I have a table that has around 70 columns , and they are by default set to 0 at the time of creating the table,when I add a new record via PHPmyadmin by just filling in one or two values and submitting it all the other fields are set to 0 , but I want to set all the fields to 1
many times ,so I need to set all the columns to 1 individually via PHPmyadmin
To speed-en up the process and
I tried
UPDATE tablename SET * = '1' WHERE id = '2' , but it does not work.
If anyone can provide a solution on similar lines , it would be great.
EDIT:
Is there a way without specifying all the 70 columns in the SQL statement? that what I am looking for. I do know how to update normally specifying columns in the SQL statement. Thank you.
If you are looking for a way to update all 70 columns to a single value with a short, simple statement, then I recommend that you write a stored procedure to do the update. That way you only need to write out the full update syntax once, and can re-use it over and over by calling the stored procedure.
CREATE PROCEDURE update_all_columns (p_new_value SMALLINT, p_id INT) ...
CALL update_all_columns(1,2);
Another trick is to use the information_schema.columns table to generate the update statement, making it less tedious to code the stored procedure.
Something like this:
SELECT concat('UPDATE ',
table_name,
' SET ',
group_concat(column_name separator ' = p_new_value, '),
' = p_new_value',
' WHERE id = p_id;') as sql_stmt
FROM information_schema.columns
WHERE table_schema = 'your_schema'
AND table_name = 'tablename'
AND column_name != 'id'
You have to name each column in an update statement.
How to drop multiple tables from one single database at one command.
something like,
> use test;
> drop table a,b,c;
where a,b,c are the tables from database test.
We can use the following syntax to drop multiple tables:
DROP TABLE IF EXISTS B,C,A;
This can be placed in the beginning of the script instead of individually dropping each table.
SET foreign_key_checks = 0;
DROP TABLE IF EXISTS a,b,c;
SET foreign_key_checks = 1;
Then you do not have to worry about dropping them in the correct order, nor whether they actually exist.
N.B. this is for MySQL only (as in the question). Other databases likely have different methods for doing this.
A lazy way of doing this if there are alot of tables to be deleted.
Get table using the below
For sql server - SELECT CONCAT(name,',') Table_Name FROM SYS.tables;
For oralce - SELECT CONCAT(TABLE_NAME,',') FROM SYS.ALL_TABLES;
Copy and paste the table names from the result set and paste it after the DROP command.
declare #sql1 nvarchar(max)
SELECT #sql1 =
STUFF(
(
select ' drop table dbo.[' + name + ']'
FROM sys.sysobjects AS sobjects
WHERE (xtype = 'U') AND (name LIKE 'GROUP_BASE_NEW_WORK_%')
for xml path('')
),
1, 1, '')
execute sp_executesql #sql1