Create Function fnRMatrixColorGet1(
#RMID varchar(20)
)
returns varchar(100)
as
begin
EXEC (N'SELECT ' + 'C'+#RMID + ' FROM vwemployeeget where empid='+#RMID)
return
end
As Gordon wrote in the comments, user defined functions in SQL Server can't execute dynamic SQL.
From Create User-defined Functions:
User-defined functions cannot make use of dynamic SQL or temp tables. Table variables are allowed.
However, you can create a stored procedure to do that:
CREATE PROCEDURE stpRMatrixColorGet1
(
#RMID varchar(20)
#MatrixColor varchar(100) OUTPUT
)
AS
DECLARE #Sql nvarchar(4000),
#Column sysname = N'C' + #RMID;
-- White list column name since it can't be parameterized
IF EXISTS
(
SELECT 1
FROM Information_Schema.Columns
WHERE Table_Name = 'vwemployeeget'
AND Column_Name = #Column
)
BEGIN
SET #SQL = N'SELECT #MatrixColor = QUOTENAME('+ #Column +') FROM vwemployeeget where empid = #RMID'
-- Safely execute dynamic SQL using sp_ExecuteSql
EXEC sp_ExecuteSql
#Sql,
N'#RMID varchar(20), #MatrixColor varchar(100) OUTPUT',
#RMID,
#MatrixColor OUTPUT
END
Related
This is a dynamic stored procedure that will pass the database, linked server and state. When executing this stored procedure, it runs the stored procedure on the database on the linked server and gives the results back.
Working code - here the linked server is absolute and not passed as a variable
EXECUTE MYPROC 'CA','MYDB'
CREATE PROCEDURE [dbo].[MYPROC]
(
#state varchar(2),
#DATABASE char(20)
)
AS
DECLARE #SQL #VARCHAR(MAX)
SELECT #SQL = 'use ' + #DATABASE + ';
SELECT * FROM pubs.dbo.authors WHERE state = #state'
EXEC MYLINKSERVER.master.dbo.sp_executesql
#SQL, N'#state char(2)', #state
Not working code: here the linked server is passed through a variable.
I get a "Syntax error" at #LINKEDSERVER**.**master
EXECUTE MYPROC 'CA','MYDB','MYLINKSERVER'
CREATE PROCEDURE [dbo].[MYPROC]
(
#state varchar(2),
#DATABASE char(20),
#LINKEDSERVER VARCHAR(20)
)
AS
DECLARE #SQL #VARCHAR(MAX)
SELECT #SQL = 'use ' + #DATABASE + ';
SELECT * FROM pubs.dbo.authors WHERE state = #state'
EXEC #LINKEDSERVER.master.dbo.sp_executesql
#SQL, N'#state char(2)', #state
Thanks in advance
Try this in your SP:
DECLARE #SQL VARCHAR(MAX);
SET #SQL = FORMATMESSAGE ( 'SELECT * FROM [%s].[%s].[dbo].[authors] WHERE [state] = ''%s'';', #LINKEDSERVER, #DATABASE, #state );
EXEC ( #SQL );
This would create the following SQL statement to be executed based on your sample parameters above:
SELECT * FROM [MYLINKSERVER].[MYDB].[dbo].[authors] WHERE [state] = 'CA';
I'm not sure what version of SQL Server you're running, so you may not be able to use FORMATMESSAGE, however, I'm sure you're familiar with concatenating strings.
I prefer to use OPENQUERY as it is usually much faster than using four-part query. So instead of SELECT * FROM [MYLINKSERVER].[MYDB].[dbo].[authors] WHERE [state] = 'CA';, try this:
SELECT * FROM OPENQUERY([MYLINKSERVER], '
SELECT * FROM [MYDB].[dbo].[authors] WHERE [state] = ''CA''
')
And your procedure will be something like this
CREATE PROCEDURE [dbo].[MYPROC]
(
#state CHAR(2),
#DATABASE VARCHAR(20),
#LINKEDSERVER VARCHAR(20)
)
AS
DECLARE #SQL NVARCHAR(500)
SET #SQL = N'SELECT * FROM OPENQUERY(' + QUOTENAME(#LINKEDSERVER) + ', ''
SELECT * FROM ' + QUOTENAME(#DATABASE) + '.dbo.authors WHERE state = ''''' + #state + '''''
'')'
EXEC SP_EXECUTESQL #SQL
--PRINT #SQL -- To see the final query to execute
Or you can use FORMATMESSAGE as the answer given by Critical Error.
SET #SQL = FORMATMESSAGE ('SELECT * FROM OPENQUERY([%s], ''
SELECT * FROM [%s].[dbo].[authors] WHERE [state] = ''''%s'''''');', QUOTENAME(#LINKEDSERVER), QUOTENAME(#DATABASE), #state
);
EXEC (#SQL);
Use QUOTENAME to avoid SQL injection. As the other parameter is limited to char(2), I guess it should be safe.
I know it's bad practice but the current situation requires a special character (sharp s = ß) as a column name. How can I write a SQL query which adds the column with the special character? With SSMS it adds Straße but when I run the SQL query with sqlcmd.exe through an external program it adds Straße.
This is the script:
DECLARE #Street varchar(50)='Straße';
IF NOT EXISTS(SELECT 1 FROM sys.columns
WHERE Name = N'#Street'
AND Object_ID = Object_ID(N'Document'))
BEGIN
EXECUTE
(
'ALTER TABLE dbo.Document ADD ' +
#Street + ' varchar(50) NULL
')
END
You need to use nvarchar not varchar:
DECLARE #Street sysname = N'Straße'; --synonym for nvarchar(128) NOT NULL
IF NOT EXISTS(SELECT 1 FROM sys.columns
WHERE Name = #Street --This shouldn't be a literal string
AND Object_ID = Object_ID(N'Document'))
BEGIN
DECLARE #SQL nvarchar(MAX);
SET #SQL - N'ALTER TABLE dbo.Document ADD ' QUOTENAME#(Street) + N' varchar(50) NULL;';
--Should the column be an nvarchar too, considering it's name?
EXEC sys.sp_executesql #SQL;
END;
I am using SQL Server 2012, I am going to Create Store Procedure which copies a column from a table in a variable, Could any one please tell me what is Wrong with this code?
alter Procedure Id_Fetch
#Col varchar(50)=null,
#Table VARCHAR(50)=Null,
#OrdrBy Varchar(40)=null
as
Begin
declare #TempCol nvarchar (100)
Exec(' SELECT '+#TempCol+' = '+#Col+' from ' + #Table +' order by '+#OrdrBy )
its showing error "Incorrect Syntax near '='
A little modification ...... Use TOP 1 in your select as if more than one value is returned by your select it will throw an error.
Use SYSNAME datatype for your Column names and table names.
Use QUOTENAME() function around your object name parameters, which puts square brackets [] around the passed parameter value and forces it to be treated as an object name (Protection against Sql Injection attack).
Use sp_executesql instead of EXEC and concatenating parameter values into string and executing again protects you against Sql Injection attack.
ALTER PROCEDURE Id_Fetch
#Col SYSNAME,
#Table SYSNAME,
#OrdrBy SYSNAME,
#Col_Value NVARCHAR(100) OUTPUT
AS
BEGIN
SET NOCOUNT ON;
DECLARE #Sql NVARCHAR(MAX);
SET #Sql = N' SELECT TOP 1 #Col_Value = ' + QUOTENAME(#Col)
+ N' FROM ' + QUOTENAME(#Table)
+ N' ORDER BY ' + QUOTENAME(#OrdrBy)
EXECUTE sp_executesql #Sql
,N'#Col_Value NVARCHAR(100) OUTPUT'
,#Col_Value OUTPUT
END
I have some tables for storing different file information, like thumbs, images, datasheets, ...
I'm writing a stored procedure to retrieve filename of a specific ID. something like:
CREATE PROCEDURE get_file_name(
#id int,
#table nvarchar(50)
)as
if #table='images'
select [filename] from images
where id = #id
if #table='icons'
select [filename] from icons
where id = #id
....
How can I rewrite this procedure using case when statement or should I just use table name as variable?
You can't use case .. when to switch between a table in the FROM clause (like you can in a conditional ORDER BY). i.e. so the following:
select * from
case when 1=1
then t1
else t2
end;
won't work.
So you'll need to use dynamic SQL. It's best to parameterize the query as far as possible, for example the #id value can be parameterized:
-- Validate #table is E ['images', 'icons', ... other valid names here]
DECLARE #sql NVARCHAR(MAX)
SET #sql = 'select [filename] from **TABLE** where id = #id';
SET #sql = REPLACE(#sql, '**TABLE**', #table);
sp_executesql #sql, N'#id INT', #id = #id;
As with all dynamic Sql, note that unparameterized values which are substituted into the query (like #table), make the query vulnerable to Sql Injection attacks. As a result, I would suggest that you ensure that #table comes from a trusted source, or better still, the value of #table is compared to a white list of permissable tables prior to execution of the query.
Just build SQL string in another variable and EXECUTE it
DECLARE #sql AS NCHAR(500)
SET #sql=
'SELECT [filename] '+
' FROM '+#table+
' WHERE id = #id'
EXECUTE(#sql)
CREATE PROCEDURE get_file_name(
#id int,
#table nvarchar(50)
)as
DECLARE #SQL nvarchar(max);
SET #SQL = 'select [filename] from ' + #table + ' where id = ' + #id
EXECUTE (#SQL)
Hi I am writing a large stored procedure, which creates a dynamic report table, of n columns in size, the first 6 are constant the remainder depend on a few arguments passed to the procedure to create the table with the required columns.
The problem that I am having is with the following TSQL
DECLARE #columnname VARCHAR(50)
SET #columnname = 'on_' + #description
IF NOT EXISTS(SELECT * FROM syscolumns WHERE id = OBJECT_ID('reports')
AND NAME = #columnname)
BEGIN
ALTER TABLE reports ADD #columnname VARCHAR(50) NULL
END
I am getting syntax errors with this at the #columnname in the ALTER TABLE statement of the above code.
Also as I am new to this, I am not sure if this is the best way to do this, or if there are better ways in TSQL to generate the required dynamic table.
Try this:
declare #sql nvarchar(100)
set #sql = 'ALTER TABLE reports ADD '+ #columnname+' VARCHAR(50) NULL'
exec sp_executesql #sql
Try
DECLARE #columnname VARCHAR(50)
SET #columnname = '[on_' + #description +']'
IF NOT EXISTS(SELECT * FROM syscolumns WHERE id = OBJECT_ID('reports')
AND NAME = #columnname)
BEGIN
ALTER TABLE reports ADD #columnname VARCHAR(50) NULL
END
Cannot get around having to do it dynamically I believe so change your BEGIN block to something like this:
DECLARE #sql VARCHAR(8000)
BEGIN
SET #sql = 'ALTER TABLE Table_1 ADD '+#columnname+' VARCHAR(50) NULL'
EXEC(#sql)
END