batch compress all tables in SQL Server - sql-server

Running into a problem with the code below. I'm trying to batch compress all tables in a certain database, but there's an issue with my syntax...
USE backups
GO
DECLARE #tables TABLE ( TABLE_NAME VARCHAR(MAX) )
INSERT INTO #tables ( TABLE_NAME ) SELECT DISTINCT TABLE_NAME FROM information_schema.TABLES
WHILE ( SELECT COUNT(*) ct FROM #tables ) > 0
BEGIN
DECLARE #table VARCHAR(MAX) = ( SELECT TOP 1 TABLE_NAME FROM #tables )
DELETE FROM #tables WHERE TABLE_NAME = #table
BEGIN TRY
ALTER TABLE #table REBUILD PARTITION = ALL WITH ( DATA_COMPRESSION = PAGE )
END TRY
BEGIN CATCH
RAISERROR( 'Compression failed for backup table : %s', 20, 101, #table ) WITH LOG
END CATCH
END
The error I'm getting is:
Incorrect syntax near '#table'. Expecting '.', ID, or QUOTED_ID

Turns out I found that you can't use variable names for tables or other schema objects in some situations. This fixes the problem...
USE backups
GO
DECLARE #tables TABLE ( TABLE_NAME NVARCHAR(MAX) )
DECLARE #query NVARCHAR(MAX)
INSERT INTO #tables ( TABLE_NAME ) SELECT DISTINCT TABLE_NAME FROM information_schema.TABLES
WHILE ( SELECT COUNT(*) ct FROM #tables ) > 0
BEGIN
DECLARE #table VARCHAR(MAX) = ( SELECT TOP 1 TABLE_NAME FROM #tables )
DELETE FROM #tables WHERE TABLE_NAME = #table
BEGIN TRY
SET #query = N'ALTER TABLE ' + #table + N' REBUILD PARTITION = ALL WITH ( DATA_COMPRESSION = PAGE )'
EXEC sp_executesql #query
END TRY
BEGIN CATCH
RAISERROR( 'Compression failed for backup table : %s', 20, 101, #table ) WITH LOG
END CATCH
END

I did a slight update in line 3 by adding where TABLE_TYPE= 'BASE TABLE' at the end, so the full line 3 looks like:
INSERT INTO #tables ( TABLE_NAME ) SELECT DISTINCT TABLE_NAME FROM information_schema.TABLES where TABLE_TYPE= 'BASE TABLE'

Related

Conditional script with for non existing column (yet)?

I'm using SQL server for creating script to run in production .
If a table doesn't contain a specific column, then create that column.
I've already did that :
IF NOT EXISTS (
SELECT 1
FROM INFORMATION_SCHEMA.columns
WHERE COLUMN_NAME = 'SeeMaxDaysBackwardPrice'
AND TABLE_NAME = 'tblsubscriptiontype'
)
BEGIN
ALTER TABLE dbo.tblsubscriptiontype ADD SeeMaxDaysBackwardPrice INT NULL
END
But now I want to insert a new row to that modified table . So now my script looks like this :
IF NOT EXISTS (
SELECT 1
FROM INFORMATION_SCHEMA.columns
WHERE COLUMN_NAME = 'SeeMaxDaysBackwardPrice'
AND TABLE_NAME = 'tblsubscriptiontype'
)
BEGIN
ALTER TABLE dbo.tblsubscriptiontype ADD SeeMaxDaysBackwardPrice INT NULL
SET IDENTITY_INSERT [dbo].[tblSubscriptionType] ON;
BEGIN TRANSACTION
INSERT INTO [dbo].[tblSubscriptionType]
(
...
[SeeMaxDaysBackwardPrice] <-------- ERROR
)
SELECT ...
-365
COMMIT;
RAISERROR (
N'[dbo].[tblSubscriptionType]: Insert Batch: 1.....Done!',
10,
1
)
WITH NOWAIT;
SET IDENTITY_INSERT [dbo].[tblSubscriptionType] OFF;
END
GO
But now I get an error ( which I perfectlly understand) :
Msg 207, Level 16, State 1, Line 29
Invalid column name 'SeeMaxDaysBackwardPrice'.
Sure I can split the script into 2 seperate scripts , but then I'll have this condition twice :
IF NOT EXISTS (
SELECT 1
FROM INFORMATION_SCHEMA.columns
WHERE COLUMN_NAME = 'SeeMaxDaysBackwardPrice'
AND TABLE_NAME = 'tblsubscriptiontype'
)
Question:
Is there any way to make SQL more relaxed about a column that do not exists yet ? (I already know about dynamic query (text) , but I wonder if there is another option.
Just wrap the code in dynamic T-SQL statement:
IF NOT EXISTS (
SELECT 1
FROM INFORMATION_SCHEMA.columns
WHERE COLUMN_NAME = 'SeeMaxDaysBackwardPrice'
AND TABLE_NAME = 'tblsubscriptiontype'
)
BEGIN
ALTER TABLE dbo.tblsubscriptiontype ADD SeeMaxDaysBackwardPrice INT NULL
SET IDENTITY_INSERT [dbo].[tblSubscriptionType] ON;
DECLARE #DynamicTSQLStatement NVARCHAR(MAX);
SET #DynamicTSQLStatement = N'
INSERT INTO [dbo].[tblSubscriptionType]
(
...
[SeeMaxDaysBackwardPrice]
)
SELECT ...
-365
';
BEGIN TRY
BEGIN TRAN;
EXEC sp_executesql #DynamicTSQLStatement;
COMMIT TRAN;
END TRY
BEGIN CATCH
ROLLBACK TRAN;
END CATCH
SET IDENTITY_INSERT [dbo].[tblSubscriptionType] OFF;
END
GO

To check whether the table exists or not dynamically

DECLARE #DROP VARCHAR(MAX)
DECLARE #TAB VARCHAR(MAX)='Employees'
DECLARE #CREATE VARCHAR(MAX)
DECLARE #SELECT VARCHAR(MAX)
--IF OBJECT_ID('DBO.'+#TAB,'U') IS NOT NULL
--BEGIN
IF (EXISTS (SELECT 1
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = 'dbo'
AND TABLE_NAME = #TAB))
BEGIN
SET #DROP = N'DROP TABLE '+#TAB
EXEC(#TAB)
END
SET #CREATE= 'CREATE TABLE '+#TAB+
'(
ID INT
,NAME VARCHAR(50)
,PHONE VARCHAR(25)
,ADDRESS VARCHAR(100)
)'
EXEC(#CREATE)
SET #SELECT='SELECT * FROM '+#TAB
EXEC(#SELECT)
I get an error, why?
Msg 2809, Level 16, State 1, Line 1
The request for procedure 'Employees' failed because 'Employees' is a table object.
You did only one mistake instead of using EXEC(#TAB) You should use EXEC(#DROP)
DECLARE #DROP VARCHAR(MAX)
DECLARE #TAB VARCHAR(MAX)='Employees'
DECLARE #CREATE VARCHAR(MAX)
DECLARE #SELECT VARCHAR(MAX)
--IF OBJECT_ID('DBO.'+#TAB,'U') IS NOT NULL
--BEGIN
IF
(EXISTS
(
SELECT
1
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = 'dbo'
AND TABLE_NAME = #TAB
)
)
BEGIN
SET #DROP=N'DROP TABLE '+#TAB
print #DROP
EXEC(#DROP)
END
SET #CREATE=
'CREATE TABLE '+#TAB+
'(
ID INT
,NAME VARCHAR(50)
,PHONE VARCHAR(25)
,ADDRESS VARCHAR(100)
)'
EXEC(#CREATE)
SET #SELECT='SELECT * FROM '+#TAB
EXEC(#SELECT)
From SQL Server 2016 SP1 onwards, objects can DIE - Drop If Exists. So, for your case, you can skip the existence check, and in the dynamic SQL to build only the following T-SQL statement:
...
'DROP TABLE IF EXISTS ' + #TAB + ';' +
'CREATE TABLE ' + #TAB +
...
Literally every object can DIE, you can get more details here:

Drop multiple columns using subquery within alter table

I need to drop all but few columns from a table while I don't know number and names of these columns in advance. I want to get column names from sys.columns and then drop all columns except few. I need something like this:
alter table Table
drop column (
select a.name as ColumnName
from sys.all_columns a
INNER JOIN sys.tables b
on a.object_id = b.object_id
where b.name = 'Table'
where a.name NOT IN (
RowID,
RemoteUserId,
Email,
FirstName,
)
)
First You need to Create a Function to Split the Comma Separated Strings to Rows
CREATE FUNCTION [dbo].[FnSplit]
(
#List nvarchar(2000),
#SplitOn nvarchar(5)
)
RETURNS #RtnValue table
(
Id int identity(1,1),
Value nvarchar(100)
)
AS
BEGIN
While (Charindex(#SplitOn,#List)>0)
Begin
Insert Into #RtnValue (value)
Select
Value = ltrim(rtrim(Substring(#List,1,Charindex(#SplitOn,#List)-1)))
Set #List = Substring(#List,Charindex(#SplitOn,#List)+len(#SplitOn),len(#List))
End
Insert Into #RtnValue (Value)
Select Value = ltrim(rtrim(#List))
Return
END
GO
Then Create Below Stored Procedure
Create Procedure DropColumnExceptGivn
#table varchar(50),
#Column Varchar(max)
AS
BEGIN
SET NOCOUNT ON;
declare #variables AS TABLE (cols varchar(max))
declare #sql varchar(max) = ''
declare #sql1 varchar(max) = ''
declare #cols nvarchar(max) =''
set #sql1 = 'SELECT Stuff((select '',''+ Column_name '+'from INFORMATION_SCHEMA.COLUMNS where
table_name = ' +''''+#table+''''+
' and column_name not in (SELECT Value FROM dbo.FnSplit('+''''+#column+''''+','',''))
for xml path('''')),1,1,'''')'
print #sql1
insert into #variables
exec (#sql1)
select #cols = cols from #variables
select #cols
set #sql= 'alter table '+ #table + ' drop column ' + #cols
print #sql
exec (#sql)
end
go
--Creating a Sample Table
Create table pets1 (petid int, PetTypeID int, PetName Varchar(20),OwnerId int)
go
Then Execute the below Stored Procedure.
The Parameters are : 1. Table Name 2. The Columns need to be Left (Comma Seperated values)
exec DropColumnExceptGivn 'pets1','PetID, PetTypeID'
go
select *from pets1
Hope This will helps

how to get all the tables from sql server database if a column name exists in the table and save the table data in a temporary table

I am trying to write a windows service, which will send automatic emails. all the tables which require email sending have common columns 'templateid' and 'emailstatus'. I want to iterate through all the tables and get the tables which has column name 'templateid'.
Now that i have the list of tables with column name 'templateid' get the data from each table whose email status is 'false' and save it in a temporary table.
if 'table1' has 4 rows of data, the temporary table should have 4 rows. after iterating through the next table the row collection should be added to the same temporary table.
IF (SELECT object_id('TempDB..#TEMPTABLE')) IS NOT NULL
BEGIN
DROP TABLE #TEMPTABLE
END
CREATE TABLE #TEMPTABLE(
[ID] INTEGER IDENTITY(1,1) NOT NULL,
[TABLE_NAME] VARCHAR(1000)
)
INSERT INTO #TEMPTABLE(TABLE_NAME)
SELECT TABLE_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE COLUMN_NAME = 'TEMPLATEID'
SELECT * FROM #TEMPTABLE
DECLARE #ROWCOUNT INT
SET #ROWCOUNT = (SELECT COUNT(ID) FROM #TEMPTABLE)
DECLARE #I INT
SET #I=1
WHILE(#I<=#ROWCOUNT)
BEGIN
DECLARE #TABLENAME VARCHAR(500)
SELECT #TABLENAME=TABLE_NAME FROM #TEMPTABLE WHERE ID=#I
EXEC('SELECT * FROM '+#TABLENAME)
SET #I=#I+1
END
i found the above query which is giving me all the tables. after that i am clueless how to proceed further as i am not good with sql server.
Not sure you are still looking for an answer but the following code will give you a temporary table with just the tables that have a column named 'templateid'. From here you would need a cursor as Tanner suggested to loop through each table and then insert records from each table (into your final target table) where email status = 'false'.
Here is the code that gets you the temp tables with columns named 'templateid' along with a sample for your cursor:
declare #max_tables int
declare #max_columns int
declare #sql nvarchar(400)
declare #x int
declare #y int
declare #table varchar(50)
declare #columns varchar(800)
declare #tablename varchar(100)
create table #c ([Table] varchar(50),[Columns] varchar(800))
select ROW_NUMBER() OVER(ORDER BY name) AS Row, name
into #table_list
from sys.objects
where type_desc = 'USER_TABLE'
order by name
set #max_tables = (select count(*) from sys.objects where type_desc = 'USER_TABLE')
set #y = 0
while #y < #max_tables
begin
set #y = #y + 1
set #table = (select name from #table_list where row = #y)
create table #t (c int)
set #sql = 'select count(*) as c from Information_schema.Columns where table_name = ''' + #table + ''''
insert into #t exec sp_executesql #sql
set #max_columns = (select top 1 c from #t)
DROP TABLE #t
set #x = 0
set #columns = ''
while #x < #max_columns
begin
set #x = #x + 1
set #columns = #columns + (select column_name from Information_schema.Columns where table_name = #table and ordinal_position = #x)
if #x < #max_columns set #columns = #columns + ', '
end
insert into #c select #table,#columns
end
select * into #tables from #c c
where c.Columns like '%templateid%'
declare my_cursor cursor for
select table from #t
open my_cursor
fetch next from my_cursor into #tablename
while ##fetch_status = 0
begin
--do something here to retrieve your data from each table and
--insert into target table
end
close my_cursor
deallocate my_cursor
DROP TABLE #c,#tables,#table_List

Drop multiple tables with string

I have tables like lg-010-a..., lg-010-ac..., and so on, I have abc database,
I have a command window:
drop table from abc where Table_Name like 'lg-010-%'
Will this drop all the tables starting with lg-010-?
Try something like this:
declare #sql varchar(max)
declare #tablenames varchar(max)
select #tablenames = coalesce(#tablenames + ', ','') + Table_Name from INFORMATION_SCHEMA.TABLES
where Table_Name like ('lg-010-%')
set #sql = 'drop table ' + #tablenames
exec (#sql)
This queries the INFORMATION_SCHEMA.TABLES table to retrieve table names that match your criteria, then concatenates them together into a comma delimited string.
This string is than added to a 'Drop table ' statement and executed.
Drop table can take multiple comma delimited table names.
(I had originally had this query sys.tables but some research revealed that while they are currently equivalent, the Information_Schema method is quaranteed to work in future versions)
Unfortunately you can't do it like that. One way is:
SELECT 'DROP TABLE ' + name FROM sysobjects WHERE name LIKE '%lg-010-a%' AND [type] IN ('P')
This will just print out the DROP TABLE statement for each table - you can then copy and paste this output and run it. You can just put an EXECUTE in the loop instead of the PRINT, but I've done it this way so you can see what's going on/check the output first.
I had an issue where the accepted answer was not doing anything. I discovered that I had to add the prefix name of the database to the code to get it to work. If your tables are not dbo.tablename try this.
declare #sql varchar(max)
declare #tablenames varchar(max)
SELECT
#tablenames = COALESCE(#tablenames + ', ','') + 'YourDatabaseName.' + Table_Name
FROM
INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE = 'BASE TABLE'
AND TABLE_NAME LIKE 'AP2%'
AND (RIGHT(TABLE_NAME, 6) < 201708)
SET #sql = 'drop table ' + #tablenames
EXEC (#sql)
GO
Unfortunately you can't do it like that.
One way is:
DECLARE #TableName NVARCHAR(128)
SELECT TOP 1 #TableName = TABLE_NAME
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME LIKE 'lg-010-%'
ORDER BY TABLE_NAME ASC
WHILE (##ROWCOUNT > 0)
BEGIN
PRINT 'DROP TABLE [' + #TableName + ']'
SELECT TOP 1 #TableName = TABLE_NAME
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME LIKE 'lg-010-%'
AND TABLE_NAME > #TableName
ORDER BY TABLE_NAME ASC
END
This will just print out the DROP TABLE statement for each table - you can then copy and paste this output and run it. You can just put an EXECUTE in the loop instead of the PRINT, but I've done it this way so you can see what's going on/check the output first.
CREATE PROCEDURE dbo.drop_MsSqlTables1 #createDate smalldatetime
AS
declare #flag int =1
declare #tname varchar(50)
declare #sql varchar(max)
select row_number() over (order by name) as num, '[dbo].[' + name +']' as table_name into #temp from sys.tables where name like ('EmpInfo_%') and create_date<#createDate
declare #count int = (select count(*) from #temp)
select * from #temp
while #flag <= #count
begin
set #tname = (select table_name from #temp where num = #flag)
set #sql = 'drop table ' + #tname
exec (#sql)
set #flag = #flag+1
end

Resources