Delete data form multiple unknown tables in SQL Server? - sql

I'm trying to delete specific data from any tables in my SQL Server.
DB like this. I want to delete all Romios.
Dog.table
(NAME,AGE) = {(Romio,2), (Juliet,3)}
Cat.table
(NAME, Fur) = {(Romio,short), (Trump, bald)}
Cow.table
(Name, Mlik) = {(Romio, 10L), (Obama, 2L)}
Useless.table
(Use1, Use2) = {...}
So, I got tables list with the below code:
SELECT TABLE_NAME FROM information_schema.COLUMNS where COLUMN_NAME = 'NAME'
But, the next step doesn't work.
DELETE (SELECT TABLE_NAME FROM information_schema.COLUMNS where COLUMN_NAME = 'NAME') WHERE Name = 'Romio'
Yeah..... I know delete query only works for 1 table. That query has a problem.
How can I make it work?

Try this if you don't mind using dynamic TSQL, i.e. using EXEC
DECLARE #StrQuery nvarchar(MAX)
SELECT #StrQuery = ISNULL(#StrQuery, '') + 'DELETE [' + TABLE_SCHEMA + '].[' + TABLE_NAME + '] WHERE NAME = ''Romio'' ' FROM information_schema.COLUMNS where COLUMN_NAME = 'NAME'
EXEC(#StrQuery)

Related

DELETE FROM AllTables Where ColumnName="Some Text"

I'm working with some databases and I have quite a few items I need to remove from them. There are about 300 or so tables in each database and I am trying to find a way to drop the rows that contain the string I need to remove.
DELETE FROM TableName WHERE ColumnName='Some String'
Works just fine, but I do not want to run that for each table. I'm hoping there is a way to do something like:
DELETE FROM * WHERE ColumnName='Some String'
I have been searching around on Google and have come accross several articles on how to drop all of the data in all the tables, which is not what I am trying to accomplish.
I am using MS SQL Server 2014.
I am still somewhat new to SQL and I don't know if there is already a way to this and I am just not using the write search terms to find it.
Thank you for your assistance.
This works for other databases, too - on other databases, you only have to change the syntax for the concatenation from + to || and change schema and name of the COLUMNS system view / table.
Run the query to a report on file. Remove any headers/footers. Then, run that file as a SQL script.
SELECT
'DELETE FROM ' + table_catalog
+ '.' + table_schema
+ '.' + table_name
+ ' WHERE ' + column_name
+ ' = ''Some String'';'
FROM information_schema.columns
WHERE UPPER(column_name) = 'NAME'
;
My database, which happens to be Vertica, returns:
DELETE FROM gpb.agreement_type WHERE name = 'Some String';
DELETE FROM gpb.product WHERE name = 'Some String';
DELETE FROM gpb.account_type WHERE name = 'Some String';
DELETE FROM gpb.document_type WHERE name = 'Some String';
DELETE FROM gpb.transaction_type WHERE name = 'Some String';
DELETE FROM gpb.account WHERE name = 'Some String';
DELETE FROM public.people_with_dupes WHERE name = 'Some String';
DELETE FROM public.people WHERE name = 'Some String';
There is an undocumented (but not unknown) stored procedure called sp_MSforeachtable.
exec sp_MSforeachtable 'DELETE FROM ? WHERE ColumnName = 'Some String';
TRY: You can use this technique to get rid from the tedious job of typing code for every table. You can first retrieve all the objects which have that <column_name> and then create a loop with delete statement. Please change <column_name> with your real column name.
Please try it, I am sure it will work for you:
select id = identity(int, 1, 1), o.name INTO #object_name
from sys.objects o
inner join sys.columns c on c.object_id = o.object_id
where type = 'u' and c.name = <column_name>
declare #i int = 1, #j int = 0, #sql varchar(500)
select #j = count(*) from #object_name
while (#i <= #j)
begin
declare #tbl_name varchar(100)
select #tbl_name = name from #object_name where id = #i
set #sql = 'delete from ' + #tbl_name + ' where <column_name> = <some_string>'
--print(#sql)
exec(#sql)
set #i = #i+1
end
Delete column from single table :
ALTER TABLE table_name DROP COLUMN column_name
Delete column from multiple table :
DECLARE #SQL VARCHAR(MAX)
SELECT #SQL += 'Alter table ' + Quotename(table_catalog)
+ '.' + Quotename(table_schema) + '.'
+ Quotename(TABLE_NAME) + ' DROP column '
+ Quotename(column_name) + ';'
FROM information_schema.columns where COLUMN_NAME = 'your_column_name' --
EXEC Sp_executesql #sql

Replace NULL with empty string in SQL for ALL columns

These questions (one, two, three) all identified how to return an empty string instead of NULL for a single column:
SELECT ISNULL(ColA,'') AS ColA FROM Table1
However, I have a query that returns a whole bunch of columns that I'm too lazy to select individually (don't worry - this isn't a production query)
SELECT * FROM Table1
Is there a way to return an empty string for all columns returned by the wildcard operator?
For Example, the following naive attempt won't work:
SELECT ISNull(*,'') FROM Table1
Maybe you can use this to generate a SQL query string in order to execute it dynamically, check if this works for you:
;WITH cte AS (
SELECT 'ISNULL(' + COLUMN_NAME + ',' +
CASE
WHEN DATA_TYPE = 'bit' THEN '0'
WHEN DATA_TYPE = 'int' THEN '0'
WHEN DATA_TYPE = 'decimal' THEN '0'
WHEN DATA_TYPE = 'date' THEN '''1/1/1900'''
WHEN DATA_TYPE = 'datetime' THEN '''1/1/1900'''
WHEN DATA_TYPE = 'uniqueidentifier' THEN '00000000-0000-0000-0000-000000000000'
ELSE ''''''
END + ') AS ' + COLUMN_NAME AS columnNameIsNull
FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'TableName'
)
SELECT
stuff((
SELECT ( ', ' + columnNameIsNull )
FROM cte
FOR XML PATH( '' )
), 1, 1, '' ) AS string
Why write complicated dynamic SQL queries if you can just use Column Select (ALT+Click+drag) to perform a multiline select in your query editor?
This way, you can type ISNULL(... once for all your columns. Just make sure the columns are aligned and you should be good to go. Supported as of SQL Server Management Studio 2012. Otherwise just use Notepad++.
This code will generate the SQL needed to replace all blank values with NULL values in ALL columns of a schema.table
Just copy the output into a new Query window and run.
DECLARE #TableName nvarchar(100) = N'YourTableName'
DECLARE #SchemaName nvarchar(100) = N'YourSchemaName'
SELECT 'UPDATE ' + #SchemaName + '.' + #TableName + ' SET ' + COLUMN_NAME + ' = NULL WHERE ' + COLUMN_NAME + ' = ''''' AS UpdateSQL
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = #TableName

Set all integer columns in all tables to 0 where the value is currently null

I'm looking for a way in SQL Server to iteratively run the following query (or to achieve the same result):
UPDATE <table> SET <column> = 0 WHERE <column> IS NULL
I've used the following query to get all the columns of type 'int', but how can I achieve the above requirement?
SELECT table_name, column_name FROM information_schema.columns where data_type = 'int' and table_name not like 'v_%' and table_name not like 'sym_%'
This is reasonably simple with some dynamic sql. I would be EXTREMELY careful doing this on any system and would ask questions about why this is a good idea. I would never do this on my system but the code is actually fairly straight forward.
declare #SQL nvarchar(max) = ''
SELECT #SQL = #SQL + 'Update [' + TABLE_NAME + '] set [' + COLUMN_NAME + '] = 0 where [' + COLUMN_NAME + '] IS NULL;'
FROM information_schema.columns
where data_type = 'int'
and table_name not like 'v_%'
and table_name not like 'sym_%'
select #SQL
--exec sp_executesql #SQL

SQL: Query multiple tables with one query

I would like to query the following in SQL Server:
Select...FROM Database.dbo.[Table 1], [Table 2], [Table 3]
and so on.
Instead of writing a unique select query for each table, I would like to write one, as follows:
FROM Database.dbo.[All Tables]
What is the most effective way to do this? I imagine I would need to define All Tables somehow and point them to the static list of tables I would like to query.
Thank you
Here's a couple of examples, of the kind of thing you might want to do.
1) SIMPLEST: to list all tables, this command will generate a listing of SQL commands that you can paste into a query window and execute:
SELECT 'SELECT * FROM ' + TABLE_NAME + '; '
FROM INFORMATION_SCHEMA.TABLES
2) Adding the TABLE_NAME to each listing, and showing just the top 3 rows of each. Also, though I usually just copy/paste them, you could try capturing all in a variable, then executing the variable contents with EXECUTE:
DECLARE #SQL_CMDS NVARCHAR(MAX)
SET #SQL_CMDS = ''
SELECT #SQL_CMDS = #SQL_CMDS + CONVERT(VARCHAR(1000),
'SELECT TOP 3 [' + TABLE_NAME + '] = ''' + TABLE_NAME
+ ''' ,* FROM ' + TABLE_NAME + '; ')
FROM INFORMATION_SCHEMA.TABLES;
EXECUTE sp_executesql #SQL_CMDS
3) Putting in a WHERE clause, for all columns that might contain an order number column (if you're not sure whether it's ORDERNO or OrderNumber or Order_Num):
DECLARE #SQL_CMDS NVARCHAR(MAX)
SET #SQL_CMDS = ''
SELECT #SQL_CMDS = #SQL_CMDS + CONVERT(VARCHAR(1000),
'SELECT [' + TABLE_NAME + '] = ''' + TABLE_NAME + ''' ,* FROM [' + TABLE_NAME
+ '] WHERE [' + COLUMN_NAME + '] = ''thisValueIWant'';')
FROM INFORMATION_SCHEMA.COLUMNS
WHERE UPPER(COLUMN_NAME) LIKE '%ORDER%N%'
GROUP BY TABLE_NAME, COLUMN_NAME
ORDER BY TABLE_NAME, COLUMN_NAME;
EXECUTE sp_executesql #SQL_CMDS
Hope that helps...
instead of this:
Select...FROM Database.dbo.[Table 1], [Table 2], [Table 3]
you MUST have at least columns of the same type in each table... then you could do this:
SELECT id(or whatever column you have in common) FROM table1
union
SELECT id(or whatever column you have in common) FROM table2
union
SELECT id(or whatever column you have in common) FROM table3
etc.

Drop all tables whose names begin with a certain string

How can I drop all tables whose names begin with a given string?
I think this can be done with some dynamic SQL and the INFORMATION_SCHEMA tables.
You may need to modify the query to include the owner if there's more than one in the database.
DECLARE #cmd varchar(4000)
DECLARE cmds CURSOR FOR
SELECT 'drop table [' + Table_Name + ']'
FROM INFORMATION_SCHEMA.TABLES
WHERE Table_Name LIKE 'prefix%'
OPEN cmds
WHILE 1 = 1
BEGIN
FETCH cmds INTO #cmd
IF ##fetch_status != 0 BREAK
EXEC(#cmd)
END
CLOSE cmds;
DEALLOCATE cmds
This is cleaner than using a two-step approach of generate script plus run. But one advantage of the script generation is that it gives you the chance to review the entirety of what's going to be run before it's actually run.
I know that if I were going to do this against a production database, I'd be as careful as possible.
Edit Code sample fixed.
SELECT 'DROP TABLE "' + TABLE_NAME + '"'
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME LIKE '[prefix]%'
This will generate a script.
Adding clause to check existence of table before deleting:
SELECT 'IF OBJECT_ID(''' +TABLE_NAME + ''') IS NOT NULL BEGIN DROP TABLE [' + TABLE_NAME + '] END;'
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME LIKE '[prefix]%'
This will get you the tables in foreign key order and avoid dropping some of the tables created by SQL Server. The t.Ordinal value will slice the tables into dependency layers.
WITH TablesCTE(SchemaName, TableName, TableID, Ordinal) AS
(
SELECT OBJECT_SCHEMA_NAME(so.object_id) AS SchemaName,
OBJECT_NAME(so.object_id) AS TableName,
so.object_id AS TableID,
0 AS Ordinal
FROM sys.objects AS so
WHERE so.type = 'U'
AND so.is_ms_Shipped = 0
AND OBJECT_NAME(so.object_id)
LIKE 'MyPrefix%'
UNION ALL
SELECT OBJECT_SCHEMA_NAME(so.object_id) AS SchemaName,
OBJECT_NAME(so.object_id) AS TableName,
so.object_id AS TableID,
tt.Ordinal + 1 AS Ordinal
FROM sys.objects AS so
INNER JOIN sys.foreign_keys AS f
ON f.parent_object_id = so.object_id
AND f.parent_object_id != f.referenced_object_id
INNER JOIN TablesCTE AS tt
ON f.referenced_object_id = tt.TableID
WHERE so.type = 'U'
AND so.is_ms_Shipped = 0
AND OBJECT_NAME(so.object_id)
LIKE 'MyPrefix%'
)
SELECT DISTINCT t.Ordinal, t.SchemaName, t.TableName, t.TableID
FROM TablesCTE AS t
INNER JOIN
(
SELECT
itt.SchemaName AS SchemaName,
itt.TableName AS TableName,
itt.TableID AS TableID,
Max(itt.Ordinal) AS Ordinal
FROM TablesCTE AS itt
GROUP BY itt.SchemaName, itt.TableName, itt.TableID
) AS tt
ON t.TableID = tt.TableID
AND t.Ordinal = tt.Ordinal
ORDER BY t.Ordinal DESC, t.TableName ASC
On Oracle XE this works:
SELECT 'DROP TABLE "' || TABLE_NAME || '";'
FROM USER_TABLES
WHERE TABLE_NAME LIKE 'YOURTABLEPREFIX%'
Or if you want to remove the constraints and free up space as well, use this:
SELECT 'DROP TABLE "' || TABLE_NAME || '" cascade constraints PURGE;'
FROM USER_TABLES
WHERE TABLE_NAME LIKE 'YOURTABLEPREFIX%'
Which will generate a bunch of DROP TABLE cascade constraints PURGE statements...
For VIEWS use this:
SELECT 'DROP VIEW "' || VIEW_NAME || '";'
FROM USER_VIEWS
WHERE VIEW_NAME LIKE 'YOURVIEWPREFIX%'
EXEC sp_MSforeachtable 'if PARSENAME("?",1) like ''%CertainString%'' DROP TABLE ?'
Edit:
sp_MSforeachtable is undocumented hence not suitable for production because it's behavior may vary depending on MS_SQL version.
Here is my solution:
SELECT CONCAT('DROP TABLE `', TABLE_NAME,'`;')
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME LIKE 'TABLE_PREFIX_GOES_HERE%';
And of course you need to replace TABLE_PREFIX_GOES_HERE with your prefix.
I saw this post when I was looking for mysql statement to drop all WordPress tables based on #Xenph Yan here is what I did eventually:
SELECT CONCAT( 'DROP TABLE `', TABLE_NAME, '`;' ) AS query
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME LIKE 'wp_%'
this will give you the set of drop queries for all tables begins with wp_
CREATE PROCEDURE usp_GenerateDROP
#Pattern AS varchar(255)
,#PrintQuery AS bit
,#ExecQuery AS bit
AS
BEGIN
DECLARE #sql AS varchar(max)
SELECT #sql = COALESCE(#sql, '') + 'DROP TABLE [' + TABLE_NAME + ']' + CHAR(13) + CHAR(10)
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME LIKE #Pattern
IF #PrintQuery = 1 PRINT #sql
IF #ExecQuery = 1 EXEC (#sql)
END
Xenph Yan's answer was far cleaner than mine but here is mine all the same.
DECLARE #startStr AS Varchar (20)
SET #startStr = 'tableName'
DECLARE #startStrLen AS int
SELECT #startStrLen = LEN(#startStr)
SELECT 'DROP TABLE ' + name FROM sysobjects
WHERE type = 'U' AND LEFT(name, #startStrLen) = #startStr
Just change tableName to the characters that you want to search with.
This worked for me.
DECLARE #sql NVARCHAR(MAX) = N'';
SELECT #sql += '
DROP TABLE '
+ QUOTENAME(s.name)
+ '.' + QUOTENAME(t.name) + ';'
FROM sys.tables AS t
INNER JOIN sys.schemas AS s
ON t.[schema_id] = s.[schema_id]
WHERE t.name LIKE 'something%';
PRINT #sql;
-- EXEC sp_executesql #sql;
select 'DROP TABLE ' + name from sysobjects
where type = 'U' and sysobjects.name like '%test%'
-- Test is the table name
SELECT 'if object_id(''' + TABLE_NAME + ''') is not null begin drop table "' + TABLE_NAME + '" end;'
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME LIKE '[prefix]%'
I had to do a slight derivation on Xenph Yan's answer I suspect because I had tables not in the default schema.
SELECT 'DROP TABLE Databasename.schema.' + TABLE_NAME
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME LIKE 'strmatch%'
In case of temporary tables, you might want to try
SELECT 'DROP TABLE "' + t.name + '"'
FROM tempdb.sys.tables t
WHERE t.name LIKE '[prefix]%'
I would like to post my proposal of the solution which DROP (not just generate and select a drop commands) all tables based on the wildcard (e.g. "table_20210114") older than particular amount of days.
DECLARE
#drop_command NVARCHAR(MAX) = '',
#system_time date,
#table_date nvarchar(8),
#older_than int = 7
Set #system_time = (select getdate() - #older_than)
Set #table_date = (SELECT CONVERT(char(8), #system_time, 112))
SELECT #drop_command += N'DROP TABLE ' + QUOTENAME(SCHEMA_NAME(schema_id)) + '.' + QUOTENAME([Name]) + ';'
FROM <your_database_name>.sys.tables
WHERE [Name] LIKE 'table_%' AND RIGHT([Name],8) < #table_date
SELECT #drop_command
EXEC sp_executesql #drop_command
If your query returns more than one line, you can collect the results and merge them into a query.
declare #Tables as nvarchar(max) = '[schemaName].['
select #Tables =#Tables + TABLE_NAME +'],[schemaName].['
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE='BASE TABLE'
AND TABLE_SCHEMA = 'schemaName'
AND TABLE_NAME like '%whateverYourQueryIs%'
select #Tables = Left(#Tables,LEN(#Tables)-13) --trying to remove last ",[schemaName].[" part, so you need to change this 13 with actual lenght
--print #Tables
declare #Query as nvarchar(max) = 'Drop table ' +#Tables
--print #Query
exec sp_executeSQL #Query
Try following code:
declare #TableLst table(TblNames nvarchar(500))
insert into #TableLst (TblNames)
SELECT 'DROP TABLE [' + Table_Name + ']'
FROM INFORMATION_SCHEMA.TABLES
WHERE Table_Name LIKE 'yourFilter%'
WHILE ((select COUNT(*) as CntTables from #TableLst) > 0)
BEGIN
declare #ForExecCms nvarchar(500) = (select top(1) TblNames from #TableLst)
EXEC(#ForExecCms)
delete from #TableLst where TblNames = #ForExecCms
END
This SQL script is executed without using a cursor.