How can I truncate all tables from a MySQL Database? - sql

Is there any way to truncate all tables from a specific MySQL database name without using any other language than SQL? I mean no linux shell scripts. (why? because it will run on windows, MacOSX and linux servers).
the problem is that the client its selecting the database name from a list in a control panel webpage (wich will be displaying MySQL databases from different servers *nix and windows), and then he will want to truncate all the tables inside that database (yes that is the main task of the web form).
Alex

Ok, I solved it by myself here is the stored procedure :)
BEGIN
DECLARE done BOOLEAN DEFAULT FALSE;
DECLARE truncatestmnt TEXT; -- this is where the truncate statement will be retrieved from cursor
-- This is the magic query that will bring all the table names from the database
DECLARE c1 CURSOR FOR SELECT Concat('TRUNCATE TABLE ', TABLE_NAME) FROM INFORMATION_SCHEMA.TABLES WHERE INFORMATION_SCHEMA.TABLES.TABLE_SCHEMA = "#DatabaseName";
DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done = TRUE;
OPEN c1;
c1_loop: LOOP
FETCH c1 INTO truncatestmnt;
IF `done` THEN LEAVE c1_loop; END IF;
SET #x = truncatestmnt;
PREPARE stm1 FROM #x;
EXECUTE stm1;
END LOOP c1_loop;
CLOSE c1;
END
What I am making its calling all tables from the given database, this will help if the tables inside the given database have no pattern to follow.
So by calling DECLARE c1 CURSOR FOR SELECT Concat('TRUNCATE TABLE ', TABLE_NAME) FROM INFORMATION_SCHEMA.TABLES WHERE INFORMATION_SCHEMA.TABLES.TABLE_SCHEMA = "#DatabaseName"; and saving results into a cursor I can fetch all the TRUNCATE TABLE x statements generated by the "n" quantity of tables inside the given database, then by just preparing and executing each statement in the cursor it will truncate all the tables inside the given database.
BTW #DatabaseName must be given as parameter to the stored procedure
Hope this helps someone else too :)
Alex

create procedure drop_tables_like(pattern varchar(255), db varchar(255))
begin
select #str_sql:=concat('drop table ', group_concat(table_name))
from information_schema.tables
where table_schema=db and table_name like pattern;
prepare stmt from #str_sql;
execute stmt;
drop prepare stmt;
end
then call
call drop_tables_like('%', 'dababase_name')

Related

How delete rows using a variable in SQL Server?

Hope you can help me with the issue below.
DETAILS: I am trying to create a stored procedure for my Azure Data Factory project where I can pass a variable table name through to tell SQL Server to delete rows.
This all is part of an ERP tool with transactional data. I would delete rows that are in the target, but changed in the source.
Example: rowid 1 - €100 in the target but changes in the source later to €80. Then I need to delete that row with €100 in the target and copy the new value from the source with the same rowid to the target
I'm migrating from a Oracle environment to a Microsoft environment. In Oracle I've this SQL for the stored procedure:
create or replace procedure AAAAA_delete
as
cursor c_del
is
select 'delete from ' ||table_name ||' a where not exists (select 1 from ' ||replace(table_name,'AAAAA','BBBBB') ||' b where a.rowid = b.rowid)' deletions
from all_tables
where table_name like 'AAAAA%'
and table_name not like 'AAAAA_LOAD%'
and table_name not in ('AAAAA_TIME','AAAAA_CONFIGURATION')
order by 1;
begin
for r_del in c_del
loop
execute immediate r_del.deletions;
commit;
end loop;
end;
** the names have been changed to AAAA and BBBB on purpose to publish the code **
I'm wondering how i can transform this into MS SQL.
WHY?: My whole ETL process in Azure Data Factory is based on variables. All the table names etc are stored in a metadata table. And it depends on +- 70 tables.
QUESTION: Is it possible to create a generic stored procedure to drop rows depending on the name I pass through.
Yes your code can be adapted for MS SQL;
create procedure AAAAA_delete AS
DECLARE #VARA NVARCHAR(100);
DECLARE #EXEC NVARCHAR(1000);
DECLARE CURSER CURSOR
LOCAL STATIC READ_ONLY FORWARD_ONLY
FOR
SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES
where table_name like 'AAAAA%'
and table_name not like 'AAAAA_LOAD%'
and table_name not in ('AAAAA_TIME','AAAAA_CONFIGURATION')
order by 1
OPEN CURSER
FETCH NEXT FROM CURSER INTO #VARA
WHILE ##FETCH_STATUS = 0
BEGIN
SET #EXEC = N'delete from ' +#VARA +' a where not exists (select 1 from ' + replace(#VARA,'AAAAA','BBBBB') +' b where a.rowid = b.rowid)'
EXEC(#EXEC)
FETCH NEXT FROM CURSER INTO #VARA
END
CLOSE CURSER
DEALLOCATE CURSER

Selecting multiple schemas in a select statement

The db being accessed is on Snowflake; not certain on the storage details behind the scenes.
I have a query right now that creates a new view from 41 data tables stored in separate schemas under the same database, looks something like this:
CREATE VIEW all_data AS
SELECT * FROM db.schema1.data UNION ALL
SELECT * FROM db.schema2.data UNION ALL
SELECT * FROM db.schema3.data
This query is run daily. My issue is I get new data tables added every few days and I have to go manually edit the query to include those new tables, as they're stored under separate schemas (and the naming scheme for the schemas isn't consistent either, for reasons outside my control). Is there a way I can select all the schemas inside a database with a subquery that would allow me to run the query daily without needing manual updates when new schemas + tables are added?
I'd like the resulting query to have a structure somewhat like
CREATE VIEW all_data as
SELECT * FROM [SELECT schemas from db].data
but not sure how that would work, and how to union the resulting data correctly.
Unfortunately, in Snowflake you can't dynamically construct SQL statements (yet). You can of course do what you want to achieve via a script in one of the supported languages (e.g. Python, JS), by first finding all the schemas and then constructing a full SQL statement.
Hope this helps.
You can definitely query the table and schema list available. SQL Authority has a good article on it:
http://blog.sqlauthority.com/2009/06/17/sql-server-list-schema-name-and-table-name-for-database/
In short the query winds up being along these lines to pull the list of tables and schema:
SELECT '['+SCHEMA_NAME(schema_id)+'].['+name+']'
AS SchemaTable
FROM sys.tables
Though you will have to add a database name to the where clause to point to the proper DB.
With the release of Snowflake Scripting dynamic recreation of the view inside Snowflake is now very possible.
create database dynamic_views;
create schema dynamic_views.schema_base;
create schema dynamic_views.schema1;
create table dynamic_views.schema1.data(id int) as select * from values (1);
We can use the INFORMATION_SCEMA.TABLES to find all DATA tables:
SELECT table_schema
FROM dynamic_views.information_schema.tables
WHERE table_name = 'DATA';
TABLE_SCHEMA
SCHEMA1
and now push that into a cursor and build up a view creation SQL
This SQL needs to be run in the new Snowsight Console see (Working with Classic Console):
declare
sql text;
add_union boolean := false;
c1 cursor for SELECT TABLE_SCHEMA
FROM dynamic_views.information_schema.TABLES
WHERE TABLE_NAME = 'DATA';
begin
sql := 'CREATE OR REPLACE VIEW dynamic_views.schema_base.all_data AS ';
for record in c1 do
if (add_union) then
sql := sql || 'UNION ALL ';
end if;
sql := sql || 'SELECT * FROM dynamic_views.'|| record.TABLE_SCHEMA ||'.data ';
add_union := true;
end for;
EXECUTE IMMEDIATE sql;
return sql;
end;
;
and we can use it:
select * from dynamic_views.schema_base.all_data;
ID
1
and add more:
create schema dynamic_views.schema2;
create table dynamic_views.schema2.data(id int) as select * from values (2);
rebuild:
anonymous block
CREATE OR REPLACE VIEW dynamic_views.schema_base.all_data AS SELECT * FROM dynamic_views.SCHEMA1.data UNION ALL SELECT * FROM dynamic_views.SCHEMA2.data
use it again:
select * from dynamic_views.schema_base.all_data;
ID
1
2
Note: You should not use SELECT * in production as the order of the table columns will be dependent of the create orders, and if newer tables have a different shape you view will become invalid.
So the explicit form really should be used:
'SELECT column1, column2, column4 FROM dynamic_views.'|| record.TABLE_SCHEMA ||'.data ';
for anyone who want the solution for this question this is my Idea with useing FETCH
Declare #str nvarchar(maX)
Declare #i int
Set #i =(Select max(id ) from Clinics );
set #str='';
declare #Id int
declare cur CURSOR LOCAL for
select [Id] from [dbo].[Clinics]
GROUP BY [Id]
open cur
fetch next from cur into #Id
while ##FETCH_STATUS = 0 BEGIN
if #i>#id
begin
set #str=#str+ 'sELECT '+ LTRIM(RTRIM(Convert(varchar(6),#Id))) + ',* fROM ' + quotename(LTRIM(RTRIM(CONVERT(VARCHAR(8),#Id))))+'.[Clinic_Benefits] UNION ALL ';
end
else
begin
set #str=#str+ 'sELECT '+ LTRIM(RTRIM(Convert(varchar(6),#Id))) + ',* fROM ' + quotename(LTRIM(RTRIM(CONVERT(VARCHAR(8),#Id))))+'.[Clinic_Benefits] ';
end
fetch next from cur into #Id
END
close cur
deallocate cur
print #str;
exec (#str);

Use SELECT results as a variable in a loop

I've searched here and elsewhere, and haven't found an answer yet. Hope I didn't miss it.
Using SQL Server Management Studio 2008 R2.
I have n specific databases on my server (there are other DBs as well, but I'm only interested in some of them)
Each of these databases has a table within it, which all have the same name. The only difference is the DB name. I want to aggregate these tables together to make one big table on a different database (different to the other DBs).
I can get the db names from the results of a query.
N is unknown.
Is a loop the way to go about this?
I was thinking something along the lines of the following pseudocode:
Set #dbnames = SELECT DISTINCT dbname FROM MyServer.dbo.MyTable
For each #name in #dbnames
INSERT INTO ADifferentDB.dbo.MyOtherTable
SELECT * FROM #name.dbo.table
Next name
(Clearly I'm new to using SQL variable as well, as you can see)
Your first problem is about iterating the databases: you cand do that with a cursor
Then you have another problem, executing a query where part of it is variable (database's name). You can do that with execute function.
All that is something similar to this:
DECLARE #query VARCHAR(max)
DECLARE #dbname VARCHAR(100)
DECLARE my_db_cursor CURSOR
FOR SELECT DISTINCT dbname FROM MyServer.dbo.MyTable
OPEN my_db_cursor
FETCH NEXT FROM my_db_cursor
INTO #dbname
WHILE ##FETCH_STATUS = 0
BEGIN
SET #query = 'INSERT INTO ADifferentDB.dbo.MyOtherTable
SELECT * FROM ' + #dbname + '.dbo.table'
EXECUTE(#query)
FETCH NEXT FROM my_db_cursor
INTO #dbname
END
CLOSE my_db_cursor
DEALLOCATE my_db_cursor
what you want to do is define a CURSOR for row-level operation. here is some doc
I would suggest using sp_MSForEachDB:
EXEC sp_MSForEachDB '
-- Include only the databases you care about.
IF NOT EXISTS (
SELECT *
FROM MySever.dbo.MyTable
WHERE dbname = ''?''
)
-- Exit if the database is not in your table.
RETURN
-- Otherwise, perform your insert.
INSERT INTO ADifferentDB.dbo.MyOtherTable
SELECT * FROM ?.dbo.table
'
In this case, ? is a token that is replaced with each database on the server.

SQL Server - A script to loop through all remote tables and perform "Select * into ...'

Here's what I'd like to do.
For each table in linkedserver.database whose tablename is like 'text%'
(inside loop)
A. If current_table exists locally, drop it
B. select * into table.name (local) from linkedserver.tablename (copy
schema + data)
C. Possibly check for errors and Print some text about it?
Next
Any idea if this script is possible? I'm very clueless about working with table names if it would be possible to
select * into #Variable_Storing_Table_Name
from LinkedServer.DB.#Variable_Storing_Table_Name
Well, here's how to do this using a cursor:
use database
go
declare #link_table nvarchar(255)
declare #local_table nvarchar(255)
declare table_list cursor for
select
tlink.name,
tlocal.name
from
linkedserver.database.sys.tables tlink
left outer join sys.tables tlocal on
tlink.name = tlocal.name
open table_list
fetch next from table_list into #link_table, #local_table
while ##FETCH_STATUS = 0
begin
begin try
if #local_table is not null
begin
sp_executesql N'drop table ' + quotename(#local_table)
end
sp_executesql N'select * into ' + quotename(#link_table) +
' from linkedserver.database..' + quotename(#link_table)
print #link_table + ' copied.'
end try
begin catch
print 'Error: ' + ERROR_MESSAGE()
end catch
fetch next from table_list into #link_table, #local_table
end
close table_list
deallocate table_list
While cursors should generally be avoided, here you're looking to do a lot of logic behind each and every row. So, here it is. What it does is grab all of the linked tables and match any of the local tables to those, or null if the local table doesn't exist. This places it in a cursor, which we can use to iterate through the rowset.
The fetch next command grabs the next row from our cursor and then applies your logic to it (drop it if the local table exists, then do a select * into...).
You can catch errors one of two ways. I used the try...catch block, but you can also check ##ERROR and see if it's not equal to zero. Really, whatever you feel most comfortable with.
As a disclaimer for the anti-cursor crowd: Cursors aren't evil, they're just often used improperly.
There is an undocumented SQL Server function called sp_foreachtable that might do what you want. I'm not sure if it works on linked databases though... a Web search might turn something up.

How can I get dbX.dbo.procA to run in the context of dbY?

I want to separate a specific set of stored procedures into a seperate database … sort of like a library. However, when I run these procs from another database, they appear to call objects from within the library database.
Here is some source code which demonstrates the problem
use mylibdb
go
create proc gettablecount
as
begin
declare #cnt int;
select #cnt=count(*)
from sysobjects
where xtype='U';
print 'Table count : ' + cast( #cnt as nvarchar);
end
go
use adventureworks
go
exec mylibdb.dbo.gettablecount;
print '';
select count(*) as [table count]
from sysobjects
where xtype='U';
Running that code will print out
Table count : 0
table count
71
(1 row(s) affected)
Notice the proc queries the mylibdb.dbo.sysobjects table, not adventureworks.dbo.sysobjects.
Does anybody know how I can do this without dynamic sql?
You could treat the library as code instead of database objects and create the procedures in the database schemas that use the "library". I would do this by storing your procedures and other shared db objects as CREATE scripts that you can modify and version.
dynamic sql is your safest bet, your other option is to create the proc in the model database and it will be available in every database you create after that (but not in the current ones so you will have to add the proc to those)
I've determined this cannot be done, so I saved the scripts as script files, rather than in procs.
So, my proc would be reduced to this anonymous block:
begin
declare #cnt int;
select #cnt=count(*)
from sysobjects
where xtype='U';
print 'Table count : ' + cast( #cnt as nvarchar);
end
PS-This is just a 'For The Record' type answer.
An alternative is to create sp_ procedures in the master database:
http://www.mssqltips.com/tip.asp?tip=1612