Deleting specific rows from all tables - sql-server

I have a database with a lot of tables.
In each table there is a column named "LicenseID" (bigint). How can I delete all rows, from all tables, that contain the value "2" in the column "LicenseID" ?
Best regards!

You didn't mentioned which database are you working with.
I assume it is SQL Server
First check your result with following query
SELECT * FROM table WHERE LicenseID LIKE '%2%'
or
SELECT * FROM table WHERE Contains(LicenseID, 2) > 0
Then Delete all those rows with above condition.
DELETE FROM table WHERE LicenseID LIKE '%2%'
or
DELETE FROM table WHERE Contains(LicenseID, 2) > 0
I have not tested it and don't know what type of database are you using. Answer can be little different in different databases.

You can use INFORMATION_SCHEMA.COLUMNS to generate the delete statements dynamically.
Something like this should do the trick:
DECLARE #Sql varchar(max) = ''
SELECT #Sql = #Sql + 'DELETE FROM '+ TABLE_NAME +' WHERE LicenseID = 2; '
FROM INFORMATION_SCHEMA.COLUMNS
WHERE COLUMN_NAME = 'LicenseID'
EXEC(#Sql)
The reason I've used INFORMATION_SCHEMA.COLUMNS and not INFORMATION_SCHEMA.TABLES is to prevent an error in case there is a table that doesn't contain the LicenseID column.

Related

Query a list of columns and tables from different databases in SQL Server

I have multiple databases and multiple tables in each one, how do I query a list that contains a column name, table name, and database name that matches with a key word in the column name?
Example: look for the database, table and column that has ID in the column name
WHERE column_name LIKE '%ID%'
master.sys.sp_MSforeachdb procedure executes the given command in all databases. Using that you can get columns of all databases. Question mark will be replace in every step with current database name. You can use ? everywhere in your command.
CREATE TABLE #Columns
(
database_name sysname,
table_name sysname,
column_name sysname
);
EXEC master.sys.sp_MSforeachdb '
USE [?]
INSERT #Columns (database_name, table_name, column_name)
SELECT DB_NAME(), OBJECT_NAME(c.object_id), c.name
FROM sys.columns AS c
WHERE c.name LIKE ''%ID%'''
SELECT * FROM #Columns AS c

Many table to union by loop function

I have 1000 tables and I need to union all tables
table_name like feature_20220503, feature_20220504 but it's not continuous numbers
It escape holiday
I want to use a loop function, but I don't know how to do it.
Does anyone could help.
You just need to make dynamic query like this
DECLARE #QUERY NVARCHAR(MAX) = ''
SELECT #QUERY = #QUERY+'UNION ALL SELECT * FROM '+TABLE_NAME+CHAR(13)
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE='BASE TABLE'
AND TABLE_NAME LIKE 'feature_%'
SET #QUERY = SUBSTRING(#QUERY,11,LEN(#QUERY))
INSERT INTO NewTable
EXEC(#QUERY)
Just Create new new table with the same schema as all the other tables and make sure you take only those tables from INFORMATION_SCHEMA

T-SQL Check if the database contains certain tables and columns MSSQL

My goal is to continue in the procedure only with the database selected if it contains a specific table and a specific column.
So that I don't get an error message later when selecting that this column doesn't exist.
Background:
It is the case that database A table A has a more current status than database B with table A. In database B of table A a column is missing, which is the reason for the error that this column does not exist. Which I also do not want to add.
This is my attempt so far:
exec sp_MSforeachdb
'
use [?]
IF (''?'' NOT LIKE ''%example%'' AND ''?'' NOT LIKE ''%example_two%''
AND EXISTS(Select 1 from sys.tables where name = ''Table1'')
AND EXISTS(Select 1 from sys.tables where name = ''Table2'')
AND ''?'' NOT IN (SELECT * FROM Database.dbo.Blacklist)
)
BEGIN
IF(EXISTS(SELECT myColumn FROM Table1 Where ID = 5 AND XYZ = 3)) BEGIN.....'
Even when i switch instead of
..
AND EXISTS(Select 1 from sys.tables where name = ''Table1'')
AND EXISTS(Select 1 from sys.tables where name = ''Table2'')
..
To:
SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = ''Table1''
AND COLUMN_NAME = ''MyExample''
it will not work the error log outputs: Incorrect syntax near 'TableXX'.
The error log gives me all databases that are practically checked, system databases as well.
Alternative it would also be helpful if someone knows how to use a case when in the select by trying to store an alternative value once the column does not exist e.g. like this:
'SELECT...
CASE WHEN exists(
SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS WHERE
TABLE_NAME =''TableX'' AND COLUMN_NAME = ''ColumnX'')
THEN ''ST.ColumnX''
ELSE ''0 AS ColumnX''
END
FROM ...'
I just want to select databases that have the valid table and column, whenever I don't exist I take another table, this works until I find a table where a column doesn't exist, the column is however my select statement therefore I get an error, I want to focus on the alternative question, is there a way to check if the column exists in the current table? before assigning a value?
Case WHEN ColumnX exists THEN (ValueOfColumnX) ELSE 0 END AS Column.
Thank you in advance for any help
Use one single quotes when you are specifying the names of your tables and columns
SELECT 1 FROM your_databasename.INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'Table1'
AND COLUMN_NAME = 'MyExample'
If you want to check if a column exists in a table try looking into this thread

T-SQL query to return results into single table

I am running a query against all databases within an instance. There are a few hundered databses with identical schema (tables and all).
This is the query:
EXEC sp_MSforeachdb 'Use ? SELECT top 1 Column1, Column2 from [TableName]where Column3 = ''SpecificValue'' order by Column4 desc'
The query works alright and returns the results which I want, but not in a way I want them.
After I run this query, in the results pane I get one mini table per database so I end up with a few hundered mini tables. It's very impractical, and it forces me to copy results one by one.
Is there a way to rewrite this query so that it returns all results inone table with 2 columns. I would like each row to be like
value of column 1 from db 1 \ value of column2 dfrom db1
value of column 1 from db 2 \ value of column2 dfrom db2
value of column 1 from db 3 \ value of column2 dfrom db3
and so on...
You can use a global temp table for this:
CREATE TABLE ##tmpTable(DBName VARCHAR(MAX),Content VARCHAR(MAX));
EXEC sp_MSforeachdb 'Use ? INSERT INTO ##tmpTable SELECT TOP 1 ''?'', TABLE_NAME FROM INFORMATION_SCHEMA.TABLES'
SELECT * FROM ##tmpTable;
GO
DROP TABLE ##tmpTable;
Although there are cases where a global temp table, i.e. "##", may be warranted, I try to stray away from them. Instead, you could still use a single session-based temp table, i.e. "#", or a table variable and just take a dynamic SQL approach to the problem.
Here's an alternative:
Create a temp table, e.g. #tmp.
Create a single executable string of SQL to be run. This string will include a query for each database.
Then simply execute the SQL string.
Here is the code:
create table #tmp (
database_id int,
database_name varchar(128),
object_id int,
object_name varchar(128));
declare
#Sql varchar(max) = (
select 'insert #tmp (database_id, database_name, object_id, object_name) select ' + convert(varchar(128), database_id) + ', ''' + name + ''', object_id, name from ' + name + '.sys.objects;'
from sys.databases
where name in ('master', 'msdb', 'tempdb')
for xml path(''));
exec (#Sql);
select
database_name,
object_count = count(*)
from #tmp
group by
database_name
order by
1;
Below are the results from the group by above:
database_name object_count
--------------------- ------------
master 116
msdb 1194
tempdb 81

Need to drop a list of tables and should be made configurable in SQL SERVER

As a part of the new release, occasionally we take backups of few tables and then delete it over a stabilisation period.
I want to make it configurable, that is have a naming convention set up for the list of tables you want to delete and then drop it after the stabilisation period is over
Here is my plan.
Rename all the tables which I want to delete, with a suffix say "_TBR" (To be Removed).
Add a suffix with yyyymmdd format, eg. if the name of the table is EmployeeDetails, it will be EmployeeDetails_TBR_20150614.
Thus, I will create a stored procedure, that will select all the tables which has a suffix of TBR and place it into a temp table, along with date time
eg
select
name AS 'TableName',
convert (datetime, substring (name, len(name)-7,8)) as 'DeletedOn'
from
sys.tables
where
name like '%_tbr_%' and
type ='u'
now
SELECT TableName FROM #TempTable WHERE DeletedOn <=GETDATE()
This will select all the tables that are beyond the specified date.
Now, declare a cursor, and then loop in and delete it.
I will schedule a job to run this stored procedure every week, and it will take care of.
Is there any other smarter and optimized way of doing it?
One method:
CREATE PROC dbo.DropBackupTables
AS
DECLARE #DropScript nvarchar(MAX) = (
SELECT N'DROP TABLE ' + QUOTENAME(OBJECT_SCHEMA_NAME(object_id)) + N'.' + QUOTENAME(name) + N';'
FROM sys.tables
WHERE
name LIKE N'%[_]TBR[_][2][0-9][0-9][0-9][0-1][0-9][0-3][0-9]'
AND RIGHT(name, 8) <= CONVERT(char(8), GETDATE(), 112)
FOR XML PATH('')
);
EXEC sp_executesql #DropScript;
GO
Seems to me like you are over complicating things.
Instead of renaming the tables and using cursors, I would simply add another table to the database, containing the names of the tables that needs to be dropped, and the dates of the drop.
Then I would use a stored procedure to create a dynamic sql to actually drop these tables.
Something like this should do the trick:
CREATE TABLE TablesToDrop
(
Table_Name sysname PRIMARY KEY,
Delete_Date date
)
CREATE PROCEDURE DropTables
AS
BEGIN
DECLARE #Sql varchar(max) = ''
SELECT #Sql = #Sql + 'DROP TABLE '+ Table_Name +';'
FROM TablesToDrop
WHERE Delete_Date <= GETDATE()
EXEC(#Sql)
END
Note #1: be very careful about who is going to insert records to this table.
Note #2: the last table to be dropped is the TablesToDrop table...

Resources