How to execute store procedure for another DB? - sql

I have a stored procedure that should be able to be executed on any table of any database on my MS Sql Server. Most of the combination of EXEC and USE statements didn't result in anything. Here is the stored procedure:
CREATE PROCEDURE [dbo].[usp_TrimAndLowerCaseVarcharFields]
(
#Database VARCHAR(200),
#TableSchema VARCHAR(200),
#TableName VARCHAR(200)
)
AS
BEGIN
DECLARE #sSql VARCHAR(MAX)
SET #Database = '[' + #Database + ']'
SET #sSql = ''
-- Create first part of a statement to update all columns that have type varchar
SELECT #sSql = #sSql + COLUMN_NAME + ' = LOWER(RTRIM(' + COLUMN_NAME + ')), '
FROM INFORMATION_SCHEMA.COLUMNS
WHERE DATA_TYPE = 'varchar'
AND TABLE_CATALOG = #Database
AND TABLE_SCHEMA = #TableSchema
AND TABLE_NAME = #TableName
SET #sSql = 'UPDATE ' + #Database + '.' + #TableSchema + '.' + #TableName + ' SET ' + #sSql
-- Delete last two symbols (', ')
SET #sSql = LEFT(#sSql, LEN(#sSql) - 1)
EXEC(#sSql)
END
Please, advice what I have to do to execute it on [OtherDB].[TargetTable].

You can fully qualify both tables and stored procedures. In other words you can do this:
UPDATE [OtherDB].[Schema].[targetTable] SET ...
It appears you are doing this in your proc already.
You can also EXEC a stored procedure using the Fully Qualified name - e.g.
EXEC [OtherDB].[dbo].[usp_TrimAndLowerCaseVarcharFields]
Honestly, your proc looks fine, are you receiving any error messages? If so please post them. Also, make sure your user has access to the other DB.

The table name in the query you used is wrong, it is looking up into same database, but you do need to look up from different database. So the query will be as below:
SELECT #sSql = #sSql + COLUMN_NAME + ' = LOWER(RTRIM(' + COLUMN_NAME + ')), '
FROM [TargetDB].INFORMATION_SCHEMA.COLUMNS
WHERE DATA_TYPE = 'varchar'
AND TABLE_CATALOG = #Database
AND TABLE_SCHEMA = #TableSchema
AND TABLE_NAME = #TableName
-- [TargetDB] = #Database
The TargetDB will be same as your passing database (#Database)
If you want to use [TargetDB] dynamically then you need to generate sql(#sSql) and the execute the sql string.

In this case I sugest to use the 2 sp's in SQL Server:
sp_MSforeachtable
sp_MSforeachdb
for more information, please read the article in here.
hope this help.
exec #RETURN_VALUE=sp_MSforeachtable #command1, #replacechar, #command2,
#command3, #whereand, #precommand, #postcommand
exec #RETURN_VALUE = sp_MSforeachdb #command1, #replacechar,
#command2, #command3, #precommand, #postcommand
Complete script:
declare #DatabaseName varchar(max), #DatabaseCharParam nchar(1)
declare #TableSchema varchar(max)
declare #TableName varchar(max), #TableCharParam nchar(1)
set #DatabaseName='DATABASENAME'; set #DatabaseCharParam='?'
set #TableSchema='dbo'
set #TableName='TABLENAME'; set #TableCharParam='$'
-- Exemple Script to execute in each table in each database
-- Create first part of a statement to update all columns that have type varchar
DECLARE #sSql VARCHAR(MAX)
set #sSql=''
SELECT #sSql = isnull(#sSql,'') + COLUMN_NAME + ' = LOWER(RTRIM(' + COLUMN_NAME + ')),'
FROM INFORMATION_SCHEMA.COLUMNS
WHERE DATA_TYPE = 'varchar'
AND TABLE_CATALOG = #DatabaseName
AND TABLE_SCHEMA = #TableSchema
AND TABLE_NAME = #TableName
declare #EachTablecmd1 varchar(2000)
--Prepare #EachTablecmd1 the script to execution in each table using sp_MSforeachtable (ATENTION: #Command1 are limited to varchar(2000) )
--in sp_MSforeachtable #TableCharParam will be subtituted with owner i.e:[dbo].[TABLENAME]
set #sSql='update '+#TableCharParam+' set '+ left(#sSql,LEN(#sSql)-1)
set #EachTablecmd1='if '''''+ #TableCharParam +'''''=''''['+#TableSchema+'].['+#TableName+']'''' '+#sSql
--i.e.: if 'table1'='table1' update table1 set column1=LOWER(RTRIM(column1)),....
-- the #sSql for each table in a database
set #sSql ='exec sp_MSforeachtable #command1='''+#EachTablecmd1+''' ,#replacechar='''+#TableCharParam+''''
declare #EachBDcmd1 varchar(2000)
--Prepare the execution to each database using sp_MSforeachdb (ATENTION: #Command1 are limited to varchar(2000) )
set #EachBDcmd1='if '''+#DatabaseCharParam+'''='''+#DatabaseName+''' '+ #sSql
--print #EachBDcmd1
exec sp_MSforeachdb #command1=#EachBDcmd1,#replacechar=#DatabaseCharParam

Related

Iterate Through and Rename All Tables w/ Object Qualifiers MSSQL

I need to iterate through all of the tables that begin with a specific prefix to rename them. The code I've tried is below, but it ends with one of two results, either it crashes SSMS (sometimes), or I get the error message below for each table. I've tried with and with out dbo.
Can anyone tell me what I'm doing wrong or perhaps suggest a better way to do this?
No item by the name of 'dbo.prefix_TableName' could be found in the current database 'DatabaseName', given that #itemtype was input as '(null)'.
Here's the code I'm running...
SET NOCOUNT ON;
USE [DatabaseName];
DECLARE #oq NVARCHAR(5), #tableName NVARCHAR(128), #newTableName NVARCHAR(128);
SET #oq = N'prefix_';
/*
find and rename all tables
*/
DECLARE [tableCursor] CURSOR FOR
SELECT [TABLE_NAME] FROM INFORMATION_SCHEMA.TABLES
WHERE [TABLE_TYPE] = 'BASE TABLE' AND [TABLE_NAME] LIKE #oq + '%'
ORDER BY [TABLE_NAME];
OPEN [tableCursor]
FETCH NEXT FROM [tableCursor] INTO #tableName
WHILE ##FETCH_STATUS = 0
BEGIN
SET #newTableName = REPLACE(#tableName, #oq, N'');
EXEC('EXEC sp_rename ''dbo.' + #tableName + ''', ''' + #newTableName + '''');
END
CLOSE [tableCursor];
DEALLOCATE [tableCursor];
A simpler solution without cursors
declare #oq nvarchar(max) = N'prefix_'
declare #cmd nvarchar(max)
select #cmd = a from (
select 'EXEC sp_rename ''' + TABLE_NAME + ''', ''' + REPLACE(TABLE_NAME, #oq, N'') + ''' '
from INFORMATION_SCHEMA.TABLES
for xml path('')
) t(a)
exec sp_executesql #cmd
In your example nvarchar(5) causes truncation, you probably need nvarchar(7) or nvarchar(max).

How to use database name dynamically in SQL Server

I need to get all table names in SQL Server. To do this I use this code:
select TABLE_NAME
from INFORMATION_SCHEMA.TABLES
I need use dynamic database name. To do this I tried to use this code:
Declare #dbName varchar(50)='Learn'
use #dbname
go
select TABLE_NAME
from INFORMATION_SCHEMA.TABLES
But it does not work. How can I do this ?
DECLARE #dbName varchar(50)='Learn'
EXEC ('SELECT TABLE_NAME FROM ' +#dbName+'.INFORMATION_SCHEMA.TABLES');
OR SIMPLY:
SELECT TABLE_NAME FROM Learn.INFORMATION_SCHEMA.TABLES
Create this stored procedure in master db and call it
CREATE PROCEDURE custom_query_executor
#dbName VARCHAR(50)
AS
BEGIN
DECLARE #query_string nvarchar(4000);
SET #query_string = 'select TABLE_NAME from ' + CAST(#dbName AS NVARCHAR) +'.INFORMATION_SCHEMA.TABLES';
EXEC sys.sp_executesql #query_string;
END
OR you can try this
DECLARE #dbName VARCHAR(50);
SET #dbName = 'Learn';
SET #query_string = 'select TABLE_NAME from ' + CAST(#dbName AS NVARCHAR) +'.INFORMATION_SCHEMA.TABLES';
EXEC sys.sp_executesql #query_string;
DECLARE #sql varchar(max)
Declare #dbName varchar(50)='Learn'
SET #sql='
use '+#dbname+'
go
select TABLE_NAME
from INFORMATION_SCHEMA.TABLES'
exec (#sql)

How to secure dynamic SQL stored procedure?

I have a stored procedure that takes in the name of a table as a parameter and uses dynamic sql to perform the select. I tried to pass #TableName as a parameter and use sp_executesql but that threw an error. I decided to go with straight dynamic sql without using sp_executesql.
Is there anything else I should be doing to secure the #TableName parameter to avoid sql injection attacks?
Stored procedure below:
CREATE PROCEDURE dbo.SP_GetRecords
(
#TableName VARCHAR(128) = NULL
)
AS
BEGIN
/* Secure the #TableName Parameter */
SET #TableName = REPLACE(#TableName, ' ','')
SET #TableName = REPLACE(#TableName, ';','')
SET #TableName = REPLACE(#TableName, '''','')
DECLARE #query NVARCHAR(MAX)
/* Validation */
IF #TableName IS NULL
BEGIN
RETURN -1
END
SET #query = 'SELECT * FROM ' + #TableName
EXEC(#query)
END
This failed when using sp_executesql instead:
SET #query = 'SELECT * FROM #TableName'
EXEC sp_executesql #query, N'#TableName VARCHAR(128)', #TableName
ERROR: Must declare the table variable
"#TableName".
See here:
How should I pass a table name into a stored proc?
you of course can look at the sysobjects table and ensure that it exists
Select id from sysobjects where xType = 'U' and [name] = #TableName
Further (more complete example):
DECLARE #TableName nVarChar(255)
DECLARE #Query nVarChar(512)
SET #TableName = 'YourTable'
SET #Query = 'Select * from ' + #TableName
-- Check if #TableName is valid
IF NOT (Select id from sysobjects where xType = 'U' and [name] = #TableName) IS NULL
exec(#Query)

SQL Server: How to perform Rtrim on all varchar columns of a table

I have over 30 columns in my table (sql server 2008). Columns type are varchar(x). I know that in every column there is two extra spaces at the end of column value. How to use rtrim function for all columns and save this modification into this existing table?
Edit: is there a way to do it using stored procedure or cursor where I don't have to manually declare all columns?
For a generic approach, you can use a script like this to generate the statement for you, for a given table (useful if you have many columns!):
DECLARE #SQL VARCHAR(MAX)
DECLARE #TableName NVARCHAR(128)
SET #TableName = 'YourTableName'
SELECT #SQL = COALESCE(#SQL + ',[', '[') +
COLUMN_NAME + ']=RTRIM([' + COLUMN_NAME + '])'
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = #TableName
AND DATA_TYPE = 'varchar'
SET #SQL = 'UPDATE [' + #TableName + '] SET ' + #SQL
PRINT #SQL
That will just print the SQL statement out. You can either then copy + run the statement, or just EXECUTE(#SQL). This is untested, so just try it out on a test table first :)
UPDATE xxx
SET col1 = RTRIM(col1),
col2 = RTRIM(col2),
col3 = RTRIM(col3),
...
We can have stored procedure to trim specific table under specific schema. If we have different schema names other than default dbo schema, it is better to use this SP by passing schema name and table name. This performs both LTRIM and RTRIM. This SP would check char, nchar, varchar, nvarchar columns.
CREATE PROCEDURE [dbo].[TrimAllColumnsOfTable] #SchemaName Varchar(100),#TableName Varchar(100)
AS
BEGIN
DECLARE #SQL VARCHAR(MAX)
SELECT #SQL = COALESCE(#SQL + ',[', '[') +
COLUMN_NAME + ']=LTRIM(RTRIM([' + COLUMN_NAME + ']))'
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = #SchemaName AND TABLE_NAME = #TableName AND DATA_TYPE Like '%char%'
SET #SQL = 'UPDATE [' + #SchemaName + '].[' + #TableName + '] SET ' + #SQL
EXEC (#SQL)
END
USAGE: [TrimAllColumnsOfTable] 'SchemaName','TableName'
It is perfect... But remember to put also the where clause:
COLUMNPROPERTY(OBJECT_ID(TABLE_SCHEMA+'.'+TABLE_NAME),COLUMN_NAME,'IsComputed') = 0
Ohterwise you will get an error if the table has a computed column of "%char%" type!
The accepted answer works well. I ran into an issue with a temp table being named the same name. You can add
and TABLE_SCHEMA = 'dbo'
And that will get rid of collision on table names.

Rename SQL Server Schema

How can I rename a schema using SQL Server?
If you have a large number of objects in a schema, you can use something like this to generate all the changes automatically (it only does tables and views, so before you run it, you might need to expand it to SPs, UDFs, etc.)
USE SandBox
DECLARE #OldSchema AS varchar(255)
DECLARE #NewSchema AS varchar(255)
DECLARE #newLine AS varchar(2) = CHAR(13) + CHAR(10)
SET #OldSchema = 'dbo'
SET #NewSchema = 'StackOverflow'
DECLARE #sql AS varchar(MAX)
SET #sql = 'CREATE SCHEMA [' + #NewSchema + ']' + #newLine
SELECT #sql = #sql + 'GO' + #newLine
SELECT #sql = #sql + 'ALTER SCHEMA [' + #NewSchema + '] TRANSFER [' + TABLE_SCHEMA + '].[' + TABLE_NAME + ']'
+ #newLine
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = #OldSchema
SET #sql = #sql + 'DROP SCHEMA [' + #OldSchema + ']'
PRINT #sql -- NOTE PRINT HAS AN 8000 byte limit - 8000 varchar/4000 nvarchar - see comments
IF (0=1) EXEC (#sql)
You move individual objects from one schema to another via:
ALTER SCHEMA NewSchema TRANSFER OldSchema.Object;
I have combined both codes above and used cursors to not be limited by the size of the string variables, executing the commands individually. I assume you have already created the new schema and will drop the old one after certifying all is ok. It's safer... :)
DECLARE #OldSchema AS varchar(255)
DECLARE #NewSchema AS varchar(255)
SET #OldSchema = 'dbo'
SET #NewSchema = 'StackOverflow'
DECLARE #sql AS varchar(MAX)
DECLARE #Schema AS varchar(MAX)
DECLARE #Obj AS varchar(MAX)
-- First transfer Tables and Views
DECLARE CU_OBJS CURSOR FOR
SELECT TABLE_SCHEMA, TABLE_NAME
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = #OldSchema
OPEN CU_OBJS
FETCH NEXT FROM CU_OBJS
INTO #Schema, #Obj
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT #sql = 'ALTER SCHEMA [' + #NewSchema + '] TRANSFER [' + #OldSchema + '].[' + #Obj + ']'
PRINT #sql
-- EXEC (#sql)
FETCH NEXT FROM CU_OBJS
INTO #Schema, #Obj
END
CLOSE CU_OBJS
DEALLOCATE CU_OBJS
-- Now transfer Stored Procedures
DECLARE CU_OBJS CURSOR FOR
SELECT sys.schemas.name, sys.procedures.name
FROM sys.procedures,sys.schemas
WHERE sys.procedures.schema_id=sys.schemas.schema_id and sys.schemas.name = #OldSchema
OPEN CU_OBJS
FETCH NEXT FROM CU_OBJS
INTO #Schema, #Obj
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT #sql = 'ALTER SCHEMA [' + #NewSchema + '] TRANSFER [' + #Schema + '].[' + #Obj + ']'
PRINT #sql
-- EXEC (#sql)
FETCH NEXT FROM CU_OBJS
INTO #Schema, #Obj
END
CLOSE CU_OBJS
DEALLOCATE CU_OBJS
The stored procedure to rename the schema which has more tables in SQL server 2008
IF OBJECT_ID ( 'dbo.RenameSchema', 'P' ) IS NOT NULL
DROP PROCEDURE dbo.RenameSchema;
GO
CREATE PROCEDURE dbo.RenameSchema
#OLDNAME varchar(500),
#NEWNAME varchar(500)
AS
/*check for oldschema exist or not */
IF NOT EXISTS (SELECT 1 FROM sys.schemas WHERE name = #OLDNAME)
BEGIN
RETURN
END
/* Create the schema with new name */
IF NOT EXISTS (SELECT 1 FROM sys.schemas WHERE name = #NEWNAME)
BEGIN
EXECUTE( 'CREATE SCHEMA ' + #NEWNAME );
END
/* get the object under the old schema and transfer those objects to new schema */
DECLARE Schema_Cursor CURSOR FOR
SELECT ' ALTER SCHEMA ' + #NEWNAME + ' TRANSFER '+ SCHEMA_NAME(SCHEMA_ID)+'.'+ name
as ALTSQL from sys.objects WHERE type IN ('U','V','P','Fn') AND
SCHEMA_NAME(SCHEMA_ID) = #OLDNAME;
OPEN Schema_Cursor;
DECLARE #SQL varchar(500)
FETCH NEXT FROM Schema_Cursor INTO #SQL;
WHILE ##FETCH_STATUS = 0
BEGIN
exec (#SQL)
FETCH NEXT FROM Schema_Cursor INTO #SQL;
END;
CLOSE Schema_Cursor;
DEALLOCATE Schema_Cursor;
/* drop the old schema which should be the user schema */
IF #OLDNAME <> 'dbo' and #OLDNAME <> 'guest'
BEGIN
EXECUTE ('DROP SCHEMA ' + #OLDNAME)
END
GO
Execute the procedure to rename the schema:
examples:
EXECUTE RenameSchema 'oldname','newname'
EXECUTE RenameSchema 'dbo','guest'
This is a short version but works well.
declare #sql varchar(8000), #table varchar(1000), #oldschema varchar(1000), #newschema varchar(1000)
set #oldschema = 'old'
set #newschema = 'dbo'
while exists(select * from sys.tables where schema_name(schema_id) = #oldschema)
begin
select #table = name from sys.tables
where object_id in(select min(object_id) from sys.tables where schema_name(schema_id) = #oldschema)
set #sql = 'alter schema [' + #newschema + '] transfer [' + #oldschema + '].[' + #table + ']'
exec(#sql)
end
For Procedures
USE DatabaseName
DECLARE #OldSchema AS varchar(255)
DECLARE #NewSchema AS varchar(255)
SET #OldSchema = 'ComputerLearn'
SET #NewSchema = 'Basic'
DECLARE #sql AS varchar(MAX)
SET #sql = 'CREATE SCHEMA [' + #NewSchema + ']' + CHAR(13) + CHAR(10)
SELECT #sql = #sql + 'ALTER SCHEMA [' + #NewSchema + '] TRANSFER [' + sys.schemas.name + '].[' + sys.procedures.name + ']'
+ CHAR(13) + CHAR(10)
FROM sys.procedures,sys.schemas
WHERE sys.procedures.schema_id=sys.schemas.schema_id and sys.schemas.name = #OldSchema
SET #sql = #sql + 'DROP SCHEMA [' + #OldSchema + ']'
PRINT #sql
IF (0=1) EXEC (#sql)
Easiest solution that worked for me is:
I have just one schema dbo with two tables PopulationByCountrySTG and CountryRegionSTG
(1) I created a new schema by executing,
create schema stg
(2) I executed the following commands,
ALTER SCHEMA stg TRANSFER dbo.PopulationByCountrySTG;
ALTER SCHEMA stg TRANSFER dbo.CountryRegionSTG;
All done. Let me know if it works for you.. Thanks Guys.