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;
Related
I am running a cursor that executes dynamic SQL using a variable.
SET #Wk = CAST(#Cntr AS nvarchar(5))
DECLARE #params nvarchar(30) = N'#Wk nvarchar(5)'
-- .. start cursor
EXEC sp_executesql N'ALTER TABLE #Temp DROP COLUMN [WK #WK Sold]', #params, #Wk
I get the error
Msg 4924, Level 16, State 1, Line 4
ALTER TABLE DROP COLUMN failed because column 'WK #WK Sold' does not exist in table #Temp
I know that #param and #Wk work because I ran
EXEC sp_executesql N'select #Wk', #params, #Wk
and it worked. I know I can just run
EXEC ('ALTER TABLE #Temp DROP COLUMN [WK ' + #Wk + ' Sold]')
but I'd like to use sp_executesql.
Is it even possible the way I have tried?
Thank you
The problem has nothing to do with the variable here. The problem is that you think that a variable/parameter when used in the context of an object results in that variable being injected into the statement. That doesn't happen. SELECT 1 AS [#a] return return a column aliased as literally #a not a column where the alias is the value of a variable called #a.
What you need to do here is safely inject the value into the dynamic statement and ideally validate the name too:
DECLARE #Cntr SomeDataType; --I don't know what the datatype should be.
DECLARE #wk nvarchar(5),
#Column sysname;
SET #wk = #Cntr; --No need for the cast here
SET #Column = (SELECT c.name
FROM tempdb.sys.tables t
JOIN tempdb.sys.columns c ON t.object_id = c.object_id
WHERE t.[name] LIKE N'#temp%'
AND c.name = N'WK
' + #wk + N' Sold');--Does your column name really have a carriage return and line break in it?
DECLARE #SQL nvarchar(MAX) = N'ALTER TABLE #Temp DROP COLUMN ' + QUOTENAME(#Column) + N';';
EXEC sys.sp_executesql #SQL;
I have a stored procedure that I want to use but I need to pass the table name into it.
ALTER PROCEDURE [dbo].[STT_Card_Entry_Temp_Write]
#CARD_NO as VarChar(20),
#tablename as table
AS
BEGIN
Update live.scheme.sttakedm
set adjustment_quantit= (TM.expected_quantity-TM.counted)*-1,
take_sign=case left((TM.expected_quantity-TM.counted),1)
when '-' then '+'
else '-'
end,
status=''
from live.scheme.sttakedm (nolock) stt
inner join #tablename TM (NOLOCK)
on TM.card_number=#CARD_NO
and TM.sequence_number=stt.sequence_number collate database_default
and TM.product_code=stt.product_code collate database_default
and stt.kind = 'B'
truncate table #tablename
END
This is my code that currently does not work.
In SQL Server, you can phrase this as:
ALTER PROCEDURE [dbo].[STT_Card_Entry_Temp_Write] (
#CARD_NO as VarChar(20),
#tablename as table
) AS
BEGIN
declare #sql nvarchar(max);
set #sql = '
Update live.scheme.sttakedm
set adjustment_quantit = (TM.expected_quantity - TM.counted) * -1,
take_sign = (case left((TM.expected_quantity - TM.counted), 1)
when ''-'' then ''+'' else ''-''
end),
status = ''''
from live.scheme.sttakedm stt join
#tablename TM
on TM.card_number = #CARD_NO and
TM.sequence_number = stt.sequence_number collate database_default and
TM.product_code = stt.product_code collate database_default and
stt.kind = 'B'
';
set #sql = replace(#sql, '#tablename', quotename(#tablename));
exec sp_executesql #sql,
N'#CARD_NO varchar(20)',
#CARD_NO=#CARD_NO;
set #sql = 'truncate table #tablename';
set #sql = replace(#sql, '#tablename', quotename(#tablename));
exec sp_executesql #sql;
END;
I would strongly advise you from using truncate table in dynamic SQL. You can really cause some problems.
If you are truncating the table, then why not just have a canonical table name used for passing values in? Or -- better yet -- create a table type so you can pass in the table directly.
You don't mention the database engine you're using, but the feature you need is called "dynamic SQL"; Google is your friend.
I'd be very nervous about allowing truncate table #tablename in dynamic SQL, though - it's really inviting disastrous bugs.
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
I need to create about 300 columns for a table and I don't want to to it manually.
How can I do this?
I want to have columns like
Bigint1..to..Bigint60
Text1 ..to..Text60
and so on.
IF (NOT EXISTS (SELECT *
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = 'dbo'
AND TABLE_NAME = 'mytbl'))
begin
create table OBJ_AttributeValues(
ObjectID numeric(18,0) not null
);
end
else
begin
DECLARE #A INT
set #A = 1;
WHILE(#A <=60)
BEGIN
alter table OBJ_AttributeValues
add ...............................
set #A = #A+1;
END
end
What should I write instead of "..."?
You will need to use dynamic SQL for that, something like
DECLARE #SSQL VARCHAR(1000)
DECLARE #A INT
set #A = 1;
WHILE(#A <=60)
BEGIN
SET #SSQL = 'alter table OBJ_AttributeValues add Bigint' + CAST(#A as varchar) + ' bigint'
EXEC (#SSQL)
set #A = #A+1;
END
This isn't really a good idea, you should take the time to write the sql or just copy-paste the columns from Excel or something like that. You also shouldn't be using the TEXT data type, is deprecated and filled with restriction (use VARCHAR(MAX) instead if you need). That said, here is a way using dynamic SQL:
DECLARE #BigintCols NVARCHAR(MAX), #TextCols NVARCHAR(MAX)
DECLARE #Query NVARCHAR(MAX)
SET #BigintCols = ''
SET #TextCols = ''
SELECT #BigintCols = #BigintCols + N'Bigint' + CAST(number AS NVARCHAR(2)) + N' BIGINT,',
#TextCols = #TextCols + N'Text' + CAST(number AS NVARCHAR(2)) + N' TEXT,'
FROM master..spt_values
WHERE type = 'P'
AND number BETWEEN 1 AND 60
ORDER BY number
SET #Query = '
CREATE TABLE OBJ_AttributeValues(ObjectID numeric(18,0) not null,'+#BigintCols+
LEFT(#TextCols,LEN(#TextCols)-1)+')'
EXECUTE sp_executesql #Query
Oh, you should probably read about dynamic sql first.
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