MSSQL Loop through list of tables to perform alter statement - sql

My SQL is quite limited and I have a number of databases within my server, I'm wondering whether its possible to write an SQL Query to loop through a listing of table names and then alter a particular table within the database name to modify a table in that database ?
Im simply wishing to add a new column to a table called site_settings.
Does MSSQL have this ability ?

You can use the script below. It returns an alter statement for each user table (you need to change your new column type as you didn't specify it) and then executes the query.
declare #sql nvarchar(max) = ''
select #sql = #sql + 'alter table ' + name + ' add site_settings int null;'
from sys.tables where type ='U'
exec sp_executesql #sql

Related

How to create a simple stored procedure with table name as an input

I am using SQL Server 2017 and I would like to create a stored procedure with a single table name as an input variable. All I want the procedure to do is update that table in a variety of ways. This project will be done twice a year, and the columns will always be the same, so I would like to try this as a stored procedure, so I do not have to highlight several lines of code and executing each time.
Is there a simple way to pass a table name through a stored procedure which updates the table (adding columns, calculating columns, replacing nulls in columns etc). In a basic example, one task would be just replaces nulls with 0s in a column. I am not sure how to set this up though. DO I have to declare every column in the table too?
CREATE PROCEDURE updteleform
#tablename TABLE
AS
BEGIN
UPDATE #tablename
SET Recog = 0
WHERE Recog IS NULL
END
GO
I'm assuming you want to update a physical table. SQL Server table variables don't work that way, rather they are a way to pass a transient result set to a stored procedure. There is no persistence if your stored procedure does not do so.
If you are looking to update the same table, then just write the procedure to work on that table.
If you are looking to update multiple tables using the same script then you should change your procedure to accept a string parameter that would be the name of the table you want it to work on and then use dynamic SQL in your stored procedure.
Something like
CREATE PROCEDURE updteleform #tablename sysname
AS
BEGIN
DECLARE #sql NVARCHAR(MAX);
SET #sql = N'
update ' + QUOTENAME(#tablename) + '
set Recog= 0
where Recog is null;';
EXEC sp_executesql #sql;
END
GO
And then call it with something like:
EXEC updteleform #tablename = 'table1';
EXEC updteleform #tablename = 'table2';
EXEC updteleform #tablename = 'table3';
...

SQL request over multiple databases and tables

I'm having quite the problem.
The process data from our machines is stored in multiple MS SQL Databases.
It is possible to mount and unmount data which is no longer used or which should be archived.
Thats the reason, why there are multiple databases.
In each Database there exists multiple tables with the data values for one or more measuring points.
Which a JOIN Query i can get the values from one table with the corresponding table and tagname:
> SELECT HA_DATA_yyyy.R_xxxxx.time HA_DATA_yyyy.R_xxxxx.value, HA_DATA_yyyy.tags.tagname FROM HA_DATA_yyyy.R_xxxxx
> INNER JOIN HA_DATA_yyyy.RI_xxxxx ON HA_DATA_yyyy.R_xxxxx.id = HA_DATA_yyyy.RI_xxxxx.id
> INNER JOIN HA_DATA_yyyy.tags on HA_DATA_yyyy.RI_xxxxx.tag_uuid = HA_DATA_yyyy.tags.tag_uuid
> WHERE (HA_DATA_yyyy.tags.tagname like 'tagname')
yyyy - represents a number for the database
xxxxx - represents a number which is unique on the database-server, but differents in each database.
But now I'm looking for a solution to get this for all R_xxxxx tables of a database and for all mounted databases.
Is there any way to do this without external software? Just with the right query request or user defined function / stored procedure?
maybe dynamic sql is an option.
as a starting point you could use the list of databases:
insert into #dblist (dbname)
select d.name from sys.databases d where d.name like 'HA_DATA_%'
then for each database gather the list of tables to read data from (you can go with cursors or other loop as you prefer):
declare #dbname varchar(128) = ''
declare #dynsql nvarchar(max)
create table #listoftables (name varchar(128), db varchar(128))
while exists(select top 1 dbname from #dblist where dbname > #dbname order by dbname)
begin
set #dynsql = 'insert into #listoftables(name,db) select name,''' + #db + ''' from '+ #db +'.sys.tables'
exec sp_executesql #statement = #dynsql
-- move on to next db
select top 1 #dbname = dbname from #dblist where dbname > #dbname order by dbname
end
now you have a table list to loop onto to build a dynamic query to read all the data at once.
beware of the many issues you may incur using dynamic sql; here and there you can find just the first 2 results gathered with some explanations on why you have to be careful using dynamic sql.
Please have a look at the answer of this Stackoverflow question:
Archiving large amounts of old data in SQL Server
I think it might be what you need.
Update:
You can query the mounted databases by using the SQL query:
select Name into #myDatabases -- get all mounted databases into #myDatabases
from sys.databases
where (has_dbaccess(name) > 0)
and name not in ('master', 'tempdb', 'model', 'msdb')
order by 1
select * from #myDatabases -- list all mounted databases
drop table #myDatabases -- don't forget to drop it at the end
This can be used to create a dynamic SQL statement, which you execute via the sp_executesql command:
EXECUTE sp_executesql #SQL_String, #Parameter_Definition, #Param1, ..., #ParamN
The parameter definition is a string containing the list of parameter names and their datatypes.
So you can build up your own query based on the database list above and then execute it.

Insert data into database whose name is not known at execution time

As part of an application installer, I need to insert some data into an already existing database. The structure of the database is known, however the exact name is not; i.e. I know the name of the table I need to insert into and its structure, but the db name is variable.
The db name's structure is: AppDB_<version#> (ex: AppDB_V20_1_2). Unfortunately, when new major versions of this application are installed, the previous dbs are left on the server, so a query to:
SELECT name FROM master..sysdatabases WHERE name LIKE 'AppDB%'
returns multiple results.
Is it possible to create a query which inserts the same table across the entire range of results?
That is, if I have databases:
AppDB_V1
AppDB_V2
AppDB_V3
Can I write a query that effectively does:
INSERT INTO [AppDB_V1].[dbo].[TableName] ...
INSERT INTO [AppDB_V2].[dbo].[TableName] ...
INSERT INTO [AppDB_V3].[dbo].[TableName] ...
without knowing the number or names of the AppDBs beforehand?
You can use dynamic sql to build you insert statement. Take a look at sp_executesql
Query the db names. Then use a cursor to go though the database names and create a insert string. Then execute it with sp_executesql.
Hope it helps!
You could generate a dynamic sql statement thus:
declare #sql mvarchar(max);
set #sql = N'';
select #sql = #sql + N', insert into ' + quotename(db.name) + N'.dbo.Table1 from dbo.SourceTable;' + char(13);
from sys.databases db
where db.name like ...
set #sql = stuff(#sql, 1, 1, N'');
exec (#sql);

Single SQL Query to update datatypes of all columns in a table at one shot

I have a SQL Server table which has 625 columns created with different datatypes like int, varchar(25), decimal(18, 2), etc...
Now am interested in changing datatype of all columns to varchar(255). Instead of executing below query for all the columns one by one, is there a single SQL Server query to change datatypes of all columns in a table at one shot?
ALTER TABLE dbo.Employee
ALTER COLUMN FirstName VARCHAR(255) NOT NULL
Looking forward for your response.
There is no one single "magic" bullet to do this - it's an operation that's rather unusual, so it's not supported natively.
What you can do is iterate over the columns of your table from the system catalog views, create such an ALTER statement on the fly, and also execute it - something like this:
DECLARE AlterTableCursor CURSOR FAST_FORWARD
FOR
SELECT
AlterCmd = 'ALTER TABLE dbo.YourTableNameHere ALTER COLUMN ' + name + ' VARCHAR(255) NULL'
FROM
sys.columns
WHERE
object_id = OBJECT_ID('dbo.YourTableNameHere')
DECLARE #AlterTableCmd NVARCHAR(200)
OPEN AlterTableCursor
FETCH NEXT FROM AlterTableCursor INTO #AlterTableCmd
WHILE ##FETCH_STATUS = 0
BEGIN
EXEC (#AlterTableCmd)
FETCH NEXT FROM AlterTableCursor INTO #AlterTableCmd
END
CLOSE AlterTableCursor
DEALLOCATE AlterTableCursor
Replace the YourTableNameHere with your actual table name - and you should be good to go! Test this on a copy of your live data first !
is not possible. You will need to do this one by one. You can do following things -
You can create a Temporary Table with your desired columns and type.
copy the data from original table to temporary table.
delete original table
Rename you Temporary Table to your original name
I would say that it's not a good design to have 625 columns in one table, but you do what ever you have been asked to do.
You could generate a SQL string that contains multiple ALTER statements and execute it with EXEC. You have to be careful with the data conversion though. This is why it's probably better to do it in a cursor, because you can catch possible exceptions for the columns that cannot be altered. Here is a simple code which does it in two steps:
generate the SQL string;
execute it using EXEC
Code sample:
SELECT * FROM sys.columns WHERE OBJECT_NAME(object_id) = 'Employee'
DECLARE #SQL VARCHAR(MAX)
SET #SQL = (
SELECT '
ALTER TABLE dbo.Employee ALTER COLUMN ' + c.name + ' VARCHAR(255) NULL;
'
FROM sys.columns c WHERE OBJECT_NAME(object_id) = 'Employee'
FOR XML PATH(''), TYPE
).value('text()[1]', 'VARCHAR(MAX)')
PRINT #SQL
EXEC(#SQL)
SELECT * FROM sys.columns WHERE OBJECT_NAME(object_id) = 'Employee'

Dropping tables using dynamic SQL

I am having trouble with my SQL stored procedure, specifically passing in VARCHAR() as a table name using it.
My code (not working) is:
CREATE PROCEDURE DeleteUser
#Username VARCHAR(50)
AS
BEGIN
--DROP THE SURF TABLE
IF EXISTS (SELECT 1
FROM sysobjects
WHERE xtype='u' AND name=#Username + '_table')
DROP TABLE #Username + '_table'
END
GO
However, on execution it errors at the DROP TABLE #Username + '_table' line.
What could I be doing incorrectly?
I am using MS SQL Server 2008 if it matters, called from C#.
The DROP TABLE statement can't be parametrised as you are trying. You would need dynamic SQL.
DECLARE #DynSql nvarchar(max) = 'DROP TABLE ' + QUOTENAME(#Username + '_table');
EXEC(#DynSql);