I have searched and searched and cannot work out how to resolve my problem. I am actually not sure it is possible but thought I'd post here and check.
The issue:
I have a stored procedure where I make the following call (there are 2 because I was trying different things but both fail):
SET #olddate = '1606'
SET #newdate = '1706'
SET #TableName = 'sometablename'
SET #sql = 'SP_RENAME ''[DBName' + #olddate + '.dbo.' + #TableName + #olddate +'].[ColumnName' + #olddate + 'restofname]'',''[ColumnName' + #newdate + 'restofname]'''
EXECUTE sp_executesql #sql
Other option:
SET #olddate = '1606'
SET #newdate = '1706'
SET #TableName = 'sometablename'
SET #old = '[DBName' + #olddate + '.dbo.' + #TableName + #olddate+']."[ColumnName' + #olddate + 'restofname]"'
SET #new = 'ColumnName' + #newdate + 'restofname'
EXECUTE sp_rename #objname = #old,#newname = #new, #objtype = 'COLUMN'
I saved this in a stored procedure, and then ran it in another query which has a different database context and got the following error for the first:
No item by the name of '[DBName.dbo.TableName.ColumnName]' could be found in the current database '[Other database]', given that #itemtype was input as '(null)'.
and this for the second:
Either the parameter #objname is ambiguous or the claimed #objtype (COLUMN) is wrong.
Now, what I'm wondering is: can I even do this? write a stored procedure that runs sp_rename in a table in one database and then call that stored procedure from another database?
I've also tried every permutation of putting open and closed brackets, [ and ] around parts of my old and new column names. Also tried putting N before the string. It's a bit of trial and error though and thus far nothing has worked.
You cannot put your DBName and schemaName and tablename into one bracket [ ] You need to enclose each with a bracket. And dont use brackets around you new name since it will take these brackets into the name. Its a string so you can just put spaces and what you like into your name.
declare #TableName nvarchar(max)
declare #ColumName nvarchar(max)
declare #NewColumn nvarchar(max)
declare #sql nvarchar(max)
SET #NewColumn = 'newtest'
SET #ColumName = 'test'
SET #TableName = 'trassor'
SET #sql = 'SP_RENAME ''[YOURDBNAME].[YOURSCHEMANAME].['+ #TableName +'].['+#ColumName+']'', '''+#NewColumn+''', ''COLUMN'''
/* SET #sql = 'SP_RENAME ''[LegogSpass].[dbo].['+ #TableName +'].['+#ColumName+']'', '''+#NewColumn+''', ''COLUMN''' */
PRINT #SQL
EXECUTE sp_executesql #sql
First of all use a select #sql query before the sp_executesql statement to view how the dynamic statement has been formed.
This gives you an understanding of the error.
In your case the brackets have been placed in a wrong way.
Either remove them or add individually to dbname,schemaname,tablename and column.
Also, you were missing the 'column' at the end of the sp_rename statement.
declare #sql nvarchar(max),#olddate varchar(10),#newdate varchar(10),#TableName varchar(100)
SET #olddate = '1606'
SET #newdate = '1706'
SET #TableName = 'sometablename'
SET #sql = 'SP_RENAME ''DBName' + #olddate + '.dbo.' + #TableName + #olddate +'.ColumnName' + #olddate + 'restofname'',''ColumnName' + #newdate + 'restofname'',''Column'''
select #sql
EXECUTE sp_executesql #sql
Thanks for all the help. I actually figured out the issue subsequently. I know the brackets were wrong but that wasn't the issue (as I tried all sorts of different combinations of brackets and none of them worked).
set #old = #TableName +'.[ColumnName' + #olddate + 'restofname]'
set #new = 'ColumnName' + #newdate + 'restofname'
execute ('use DBName exec sp_rename ''' + #old + ''', ''' + #new + ''', ''COLUMN''')
The trick was to include "Use Database" within the execute statement.
Related
Currently I have a working version of a dynamic SQL query without any variables except one (#ColumnHeader). And am able to get the desired result being a collection of column names in one line separated by comma.
select #ColumnHeader = COALESCE(#ColumnHeader+',','') + '''' + column_name + ''''
from databaseName.Information_Schema.Columns
where table_name = 'Dates'
I am trying to add variables for Database_information_schema and TableName.
DECLARE #ColumnHeader varchar(8000)
DECLARE #Database_Information_SchemaColumns varchar(8000) = 'DatabaseName2.Information_Schema.Columns'
DECLARE #TableName varchar(8000) = 'dates'
DECLARE #sqlQuery as nvarchar(max) = 'Select ' + #ColumnHeader + '= COALESCE(' + #ColumnHeader+ +''','','''')+ ''''''''+column_name+'''''''' from ' + #Database_Information_SchemaColumns + 'where table_name = '''+ #TableName + ''''
Print #sqlQuery
EXEC sp_executesql #sqlQuery;
I am getting Null values and am not sure whats wrong here.
What follows is some working code. I explain the changes required:
You are trying to assign a parameter using dynamic SQL, therefore the parameter needs to be part of the dynamic SQL string, not concatenated with it.
To assign a parameter using dynamic SQL you have to pass it in/out of sp_executesql because the context the dynamic SQL is running under cannot see the parameters declared.
While this is not necessary, I have renamed the internal parameter so that its clear which parameter belongs in which scope. However both could use the same name if desired.
You were missing a space before your where.
I recommend using varchar(max) and nvarchar(max) as there is no need to risk running into the 8k limit.
Use quotename for any database, schema, table or column names to protect against injection.
Use the sysname datatype where a system name is being stored
Split all system names into parts to allow the use of quotename
DECLARE #ColumnHeader varchar(max)
, #Database_Information_Database sysname = 'DatabaseName2'
, #Database_Information_Schema sysname = 'Information_Schema'
, #Database_Information_Columns sysname = 'Columns'
, #TableName sysname = 'dates';
DECLARE #sqlQuery nvarchar(max) = 'select #ColumnHeaderInteral = COALESCE(#ColumnHeaderInteral,'','','''') + '''''''' + column_name + '''''''' from '
+ quotename(#Database_Information_Database) + '.'
+ quotename(#Database_Information_Schema) + '.'
+ quotename(#Database_Information_Columns)
+ ' where quotename(table_name) = ''' + quotename(#TableName) + '''';
PRINT #sqlQuery;
EXEC sp_executesql #sqlQuery, N'#ColumnHeaderInteral varchar(max) output', #ColumnHeaderInteral = #ColumnHeader out;
SELECT #ColumnHeader;
Official Documentation
Below is my procedure. It is working fine.
Create PROCEDURE [dbo].[spCompanyName]
(
#CompanyName VARCHAR(100))
AS
Begin
DECLARE #sql VARCHAR(MAX)
SET #sql = ' Select EmpID,CompanyName FROM Employee' + CHAR(13) + CHAR(10)
IF len(#CompanyName) > 0
BEGIN
SET #sql = #sql + ' Where (RTRIM(LTRIM(CompanyName)) like ''' + #CompanyName + '%'') ' + char(13) + char(10)
END
PRINT #SQL
EXEC(#sql)
End
exec spCompanyName #CompanyName='So Unique, formerly Sofia''''s'
I need Wherever single quote is there in companyname,if I pass 8 quotes in single quotes I need output.above procedure where do I need to change.
Eg:
exec spCompanyName #CompanyName='So Unique, formerly Sofia''''''''s'
exec spCompanyName #CompanyName='Absolute''''''''s,Strategy''''''''s'
Don't think "I'll throw away all of the useful features of using parameters to separate data from code and start manually trying to protect strings" - keep using parameters.
Rather than
EXEC(#sql)
Have:
EXEC sp_executesql #sql,N'#CompanyName varchar(100)',#CompanyName = #CompanyName
And change:
SET #sql = #sql + ' Where (RTRIM(LTRIM(CompanyName)) like ''' + #CompanyName + '%'') ' + char(13) + char(10)
to:
SET #sql = #sql + ' Where (RTRIM(LTRIM(CompanyName)) like #CompanyName + ''%'') ' + char(13) + char(10)
Or, in the alternative, consider just writing a normal query, no dynamic SQL:
Create PROCEDURE [dbo].[spCompanyName]
(
#CompanyName VARCHAR(100))
WITH RECOMPILE
AS
Begin
Select EmpID,CompanyName FROM Employee
Where RTRIM(LTRIM(CompanyName)) like #CompanyName + '%' or
#CompanyName is null
End
Assuming you're using SQL Server 2008 (with particular patch levels) or later, as specified in Erland Sommarskog's Dynamic Search Conditions in T-SQL
If you are going to create a new stored procedure for this feature then you can have this in much better way then dynamic.
You should execute different select queries based on if CompanyName is passed or not.
You can simply the stored procedure as following.
Create PROCEDURE [dbo].[spCompanyName]
(
#CompanyName VARCHAR(100))
AS
Begin
IF LEN(#CompanyName) > 0
BEGIN
Select EmpID,CompanyName FROM Employee WHERE RTRIM(LTRIM(CompanyName)) like '' + #CompanyName + '%'
END
ELSE
BEGIN
Select EmpID,CompanyName FROM Employee
END
END
I am not sure why you need to pass so many single quotes in the parameter value but to me it looks like you can execute the procedure with following simple way.
EXEC spCompanyName #CompanyName='So Unique, formerly Sofia''s'
EXEC spCompanyName #CompanyName='Absolute''s,Strategy''s'
This should help you finding your solution.
I am trying to create a script to create/setup a group of stored procedures that will all be fairly similar.
So I am trying to loop through this code, changing the #DATABASE_NAME and #TableName when needed.
/* Start loop */
DECLARE #create_stored_procedure nvarchar(max)
SET #create_stored_procedure = N'
USE [' + #DATABASE_NAME + ']
CREATE PROCEDURE [dbo].[sproc_imp_' + #TableName + ']
AS
BEGIN
PRINT(''doing something'')
END'
EXEC sp_executesql #statement = #create_stored_procedure
/* End loop */
But I am getting errors saying
'CREATE/ALTER PROCEDURE' must be the first statement in a query batch.
or
'CREATE/ALTER PROCEDURE' does not allow specifying the database name as a prefix to the object name.
All the solutions online suggest using GO, but that won't work in dynamic SQL.
Does anyone know a possible solution for SQL Server 2005?
I wouldn't call the solution intuitive, but apparently this works. I prefer the look of this one though.
Try with spiting USe DB and create procedure. Like this
DECLARE #create_store_procedure nvarchar(max)
SET #create_store_procedure = N'
USE [' + #DATABASE_NAME + '] '
EXEC sp_executesql #statement = #create_store_procedure
SET #create_store_procedure = N'
CREATE PROCEDURE [dbo].[sproc_imp_' + #TableName + ']
AS
BEGIN
PRINT(''doing something'')
END '
EXEC sp_executesql #statement = #create_store_procedure
This is working perfectly for me
I tried Nithesh's answer and that didn't work for me it ended up creating the store procedure in the master table. Zec's answer worked. Creating a dynamic query inside my dynamic query.
DECLARE #create_store_procedure nvarchar(max)
DECLARE #use_db nvarchar(max)
SET #create_store_procedure = N'
CREATE PROCEDURE [dbo].[sproc_imp_' + #TableName + ']
AS
BEGIN
PRINT(''doing something'')
END '
SET #use_db = N'
USE [' + #DATABASE_NAME + ']
DECLARE #sub_create_store_procedure nvarchar(max)
SET #sub_create_store_procedure = ''' + REPLACE(#create_store_procedure, CHAR(39), CHAR(39) + CHAR(39)) + '''
EXEC sp_executesql #statement = #sub_create_store_procedure
'
EXEC sp_executesql #statement = #use_db
I have a cursor which works fine but when it gets to this part of the script, it seems to still run the update even though the table doesn't exists:
SET #sql = 'IF (EXISTS (SELECT * FROM ps_vars_' + #datasetid + '))
BEGIN
UPDATE ps_vars_' + #datasetid + '
SET programming_notes = replace(programming_notes, ''Some of the variables listed are source variables.'')
END';
EXEC SP_EXECUTESQL #sql
What am I missing? The #datasetid variable gets passed in correctly too.
DECLARE #tablename sysname
SET #tablename = 'ps_vars' + #datasetid
IF (OBJECT_ID(#tablename, 'U') IS NOT NULL)
BEGIN
SET #sql = ' UPDATE ' + QUOTENAME(#tablename) + '
SET programming_notes = replace(programming_notes, ''Some of the variables listed are source variables.'') ';
EXEC sp_executesql #sql
END
When you use the EXISTS with the table name to see if the table exists you're actually trying to access the table - which doesn't exist. That's why you're getting an error, not because of your UPDATE statement.
Try this instead:
SET #sql = 'IF (OBJECT_ID(''ps_vars_' + #datasetid + ''') IS NOT NULL)
BEGIN
UPDATE ...
END'
Then think about what might be wrong with your database design that requires you to use dynamic SQL like this. Maybe your design is exactly how it needs to be, but in my experience 9 out of 10 times (probably much more) this kind of code is a symptom of a poor design.
I have a SQL script that acquires table names and creates trigger for those tables. When I open the trigger after creating it all of the code is on one line. How would I go about adding tab and new line characters within the script to make the trigger more readable.
Example code:
SET #SQL = 'ALTER TRIGGER [dbo].[TRG_' + SUBSTRING(#TABLE_NAME,5, LEN(#TABLE_NAME)) + '_$AUD] '
SET #SQL = #SQL + 'ON [dbo].[' + #TABLE_NAME + '] '
SET #SQL = #SQL + 'FOR UPDATE, DELETE '
SET #SQL = #SQL + 'AS '
SET #SQL = #SQL + 'DECLARE '
SET #SQL = #SQL + '#BIT INT, '
SET #SQL = #SQL + '#FIELD INT, '
SET #SQL = #SQL + '#CHAR INT '
For MS SQL at least, you can either use CHAR() with the correct ASCII values and concatenate at the correct places in your strings, or you can just include the newlines, tabs, etc. within your SQL strings themselves. The string can span multiple lines. For example, this should work:
SET #SQL = 'ALTER TRIGGER [dbo].[TRG_' + SUBSTRING(#TABLE_NAME,5, LEN(#TABLE_NAME)) + '_$AUD]
ON [dbo].[' + #TABLE_NAME + ']
...
'
This won't change the actual trigger definition, but you could use a tool like Instant SQL Formatter, when you need to work on it.
use this
SET #SQL = 'ALTER TRIGGER [dbo].[TRG_' + SUBSTRING(#TABLE_NAME,5, LEN(#TABLE_NAME)) + '_$AUD]
ON [dbo].[' + #TABLE_NAME + ']
FOR UPDATE, DELETE
AS
DECLARE
#BIT INT,
#FIELD INT,
#CHAR INT '