"." char throws error in sql-server - sql-server

This shouldn't be a very hard to solve problem, but I'm out pages on google to search for the solution.
I have a database with users that have their names like 'firstname.lastname'.
Example : john.smith , b.obama , v.putin and so on.
I try to add these users some roles within a SP
This is my SP :
ALTER PROCEDURE [dbo].[sp_adaugaUserInRol]
-- Add the parameters for the stored procedure here
#Rol varchar(50),
#User varchar(32)
AS
BEGIN
declare #sRol varchar(50),
#sUser varchar(32);
set #sUser = LTRIM(RTRIM(#User))
set #sRol = LTRIM(RTRIM(#Rol))
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
print(' ALTER ROLE ' + #sRol + ' ADD MEMBER ' +#User )
END
If I use a string for user like 'john' , 'obama' it works, but if I use it as 'john.smith' or 'b.obama' I get the error Incorrect syntax near '.'. , which is very logical as SQL thinks john is a table and smith is a column ( my guess ).
How can I tell SQL that john.smith is a string?

put it in square brackets:
[john.smith]

print(' ALTER ROLE [' + #sRol + '] ADD MEMBER [' +#User + ']' )

Related

Create table on the fly using select into

I am trying to use dynamic SQL to fill a temp table with data from one of several servers, depending on a declared variable. The source data may have more columns added in the future, so I'd like to be able to create the destination temp table based on what columns currently exist, without having to explicitly define it.
I tried creating an empty table with the appropriate columns using:
Select top 1 * into #tempTable from MyTable
Delete from #tempTable
Or:
Select * into #tempTable from MyTable where 1 = 0
Both worked to create an empty table, but when I then try to insert into it:
declare #sql varchar(max) = 'Select * from '
+ case when #server = '1' then 'Server1.' else 'Server2.' end
+ 'database.dbo.MyTable'
Insert into #tempTable
exec(#sql)
I get this error:
Msg 213, Level 16, State 7, Line 1
Column name or number of supplied values does not match table definition.
exec(#sql) works fine on its own. I get this error even when I use the same table, on the same server, for both steps. Is this possible to fix, or do I have to go back to explicitly defining the table with create table?
How about using global temp table. there is some disadvantage of using global temp table because it can access from multiple users and databases. ref http://sqlmag.com/t-sql/temporary-tables-local-vs-global
DECLARE #sql nvarchar(max) = 'SELECT * INTO ##tempTable FROM '
+ case when #server = '1' THEN 'Server1.' ELSE 'Server2.' END
+ 'database.dbo.MyTable'
EXECUTE sp_executesql (#sql)
SELECT * FROM ##tempTable
(Thanks to helpful commenter #XQbert)
Replacing the ID column (Int, Identity) in the temp table with a column that was just an int causes
Insert into #tempTable
exec(#sql)
to function as intended.
Both that syntax and
declare #sql varchar(max) = 'Insert into #tempTable Select * from '
+ case when #server = '1' then 'Server1.' else 'Server2.' end
+ 'database.dbo.MyTable'
exec(#sql)
worked, but making insert part of the dynamic sql produced much more helpful error messages for troubleshooting.

Add a column, with a derived column name, to an existing table in SQL Server 2014

DECLARE
#countFlag INT,
#maxNum INT = 5,
#addingName NVARCHAR(6)
SET #countFlag = 1
WHILE (#countFlag <= #maxNum)
BEGIN
SET #addingName = 'name' + CAST(#countFlag AS NVARCHAR(2))
ALTER TABLE TableName
ADD
#addingName NVARCHAR(30)
SET #countFlag = #countFlag + 1
END
========================================================
This is called at the beginning of a set of procedures. #maxNum is actually passed in based on a question to the operator and changes the 'shape' of an existing db to include more columns. I would like to have the resulting column names be something like "name1" "name2" etc. but I am getting an "Incorrect syntax near '#addingName'" after the ADD statement when I execute it. What am I doing wrong here?
You cannot do it in that way, you should compose the query dynamically and execute it with Exec:
DECLARE #sqlCommand varchar(200)
SET #sqlCommand = 'ALTER TABLE TableName ADD ' + #addingName + ' NVARCHAR(30) '
EXEC (#sqlCommand)

What is the best way to toggle user defined column name or default column name in stored procedure

What is the best approach for stored procedure to toggle between user defined column names or default column name
Here is what I have done so far. This is fine for small query, is there a better way of doing this for larger query.
-- Drop stored procedure if it already exists
IF EXISTS(SELECT * FROM sys.procedures
WHERE schema_id = schema_id('dbo')
AND name = N'sp_test')
DROP PROCEDURE dbo.sp_test
GO
CREATE PROCEDURE [dbo].[sp_test]
-- /* Declare parameters */
#columnName BIT =0
AS
BEGIN
-- SELECT statement to fetch record
IF(#columnName =1)
(
SELECT
TOP 100
IM.INC_REF,
IM.ID
FROM
dbo.TEST AS IM
)
ELSE
(
SELECT
TOP 100
IM.INC_REF AS REF,
IM.ID AS ID
FROM
dbo.TEST AS IM
)
END
GO
-- ============================================
-- Execute stored procedure
-- ============================================
DECLARE #columnName AS BIT
SET #columnName =0
EXEC [dbo].[sp_test] #columnName
Thanks in advance
When we need different results from a stored procedure based on a parameter, we'll call one of two "sub" stored procedures. In your case, that would be:
CREATE PROCEDURE [dbo].[sp_test]
-- /* Declare parameters */
#columnName BIT = 0
AS
BEGIN
IF ( #columnName = 1 )
EXEC dbo.[sp_test1]
ELSE
EXEC dbo.[sp_test2]
END
GO
CREATE PROCEDURE dbo.[sp_test1]
AS
BEGIN
SELECT TOP 100
IM.INC_REF ,
IM.ID
FROM dbo.TEST AS IM
END
GO
CREATE PROCEDURE dbo.[sp_test2]
AS
BEGIN
SELECT TOP 100
IM.INC_REF AS REF ,
IM.ID AS ID
FROM dbo.TEST AS IM
END
GO
I've found this gets around the issue of badly cached plans.

How to detect interface break between stored procedure

I am working on a large project with a lot of stored procedures. I came into the following situation where a developer modified the arguments of a stored procedure which was called by another stored procedure.
Unfortunately, nothing prevents the ALTER PROC to complete.
Is there a way to perform those checks afterwards ?
What would be the guidelines to avoid getting into that kind of problems ?
Here is a sample code to reproduce this behavior :
CREATE PROC Test1 #arg1 int
AS
BEGIN
PRINT CONVERT(varchar(32), #arg1)
END
GO
CREATE PROC Test2 #arg1 int
AS
BEGIN
DECLARE #arg int;
SET #arg = #arg1+1;
EXEC Test1 #arg;
END
GO
EXEC Test2 1;
GO
ALTER PROC Test1 #arg1 int, #arg2 int AS
BEGIN
PRINT CONVERT(varchar(32), #arg1)
PRINT CONVERT(varchar(32), #arg2)
END
GO
EXEC Test2 1;
GO
DROP PROC Test2
DROP PROC Test1
GO
Sql server 2005 has a system view sys.sql_dependencies that tracks dependencies. Unfortunately, it's not all that reliable (For more info, see this answer). Oracle, however, is much better in that regard. So you could switch. There's also a 3rd party vendor, Redgate, who has Sql Dependency Tracker. Never tested it myself but there is a trial version available.
I have the same problem so I implemented my poor man's solution by creating a stored procedure that can search for strings in all the stored procedures and views in the current database. By searching on the name of the changed stored procedure I can (hopefully) find EXEC calls.
I used this on sql server 2000 and 2008 so it probably also works on 2005. (Note : #word1, #word2, etc must all be present but that can easily be changed in the last SELECT if you have different needs.)
CREATE PROCEDURE [dbo].[findWordsInStoredProceduresViews]
#word1 nvarchar(4000) = null,
#word2 nvarchar(4000) = null,
#word3 nvarchar(4000) = null,
#word4 nvarchar(4000) = null,
#word5 nvarchar(4000) = null
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- create temp table
create table #temp
(
id int identity(1,1),
Proc_id INT,
Proc_Name SYSNAME,
Definition NTEXT
)
-- get the names of the procedures that meet our criteria
INSERT #temp(Proc_id, Proc_Name)
SELECT id, OBJECT_NAME(id)
FROM syscomments
WHERE OBJECTPROPERTY(id, 'IsProcedure') = 1 or
OBJECTPROPERTY(id, 'IsView') = 1
GROUP BY id, OBJECT_NAME(id)
-- initialize the NTEXT column so there is a pointer
UPDATE #temp SET Definition = ''
-- declare local variables
DECLARE
#txtPval binary(16),
#txtPidx INT,
#curText NVARCHAR(4000),
#counterId int,
#maxCounterId int,
#counterIdInner int,
#maxCounterIdInner int
-- set up a double while loop to get the data from syscomments
select #maxCounterId = max(id)
from #temp t
create table #tempInner
(
id int identity(1,1),
curName SYSNAME,
curtext ntext
)
set #counterId = 0
WHILE (#counterId < #maxCounterId)
BEGIN
set #counterId = #counterId + 1
insert into #tempInner(curName, curtext)
SELECT OBJECT_NAME(s.id), text
FROM syscomments s
INNER JOIN #temp t
ON s.id = t.Proc_id
WHERE t.id = #counterid
ORDER BY s.id, colid
select #maxCounterIdInner = max(id)
from #tempInner t
set #counterIdInner = 0
while (#counterIdInner < #maxCounterIdInner)
begin
set #counterIdInner = #counterIdInner + 1
-- get the pointer for the current procedure name / colid
SELECT #txtPval = TEXTPTR(Definition)
FROM #temp
WHERE id = #counterId
-- find out where to append the #temp table's value
SELECT #txtPidx = DATALENGTH(Definition)/2
FROM #temp
WHERE id = #counterId
select #curText = curtext
from #tempInner
where id = #counterIdInner
-- apply the append of the current 8KB chunk
UPDATETEXT #temp.definition #txtPval #txtPidx 0 #curtext
end
truncate table #tempInner
END
-- check our filter
SELECT Proc_Name, Definition
FROM #temp t
WHERE (#word1 is null or definition LIKE '%' + #word1 + '%') AND
(#word2 is null or definition LIKE '%' + #word2 + '%') AND
(#word3 is null or definition LIKE '%' + #word3 + '%') AND
(#word4 is null or definition LIKE '%' + #word4 + '%') AND
(#word5 is null or definition LIKE '%' + #word5 + '%')
ORDER BY Proc_Name
-- clean up
DROP TABLE #temp
DROP TABLE #tempInner
END
You can use sp_refreshsqlmodule to attempt to re-validate SPs (this also updates dependencies), but it won't validate this particular scenario with parameters at the caller level (it will validate things like invalid columns in tables and views).
http://www.mssqltips.com/tip.asp?tip=1294 has a number of techniques, including sp_depends
Dependency information is stored in the SQL Server metadata, including parameter columns/types for each SP and function, but it isn't obvious how to validate all the calls, but it is possible to locate them and inspect them.

Alter column, add default constraint

I have a table and one of the columns is "Date" of type datetime. We decided to add a default constraint to that column
Alter table TableName
alter column dbo.TableName.Date default getutcdate()
but this gives me error:
Incorrect syntax near '.'
Does anyone see anything obviously wrong here, which I am missing (other than having a better name for the column)
Try this
alter table TableName
add constraint df_ConstraintNAme
default getutcdate() for [Date]
example
create table bla (id int)
alter table bla add constraint dt_bla default 1 for id
insert bla default values
select * from bla
also make sure you name the default constraint..it will be a pain in the neck to drop it later because it will have one of those crazy system generated names...see also How To Name Default Constraints And How To Drop Default Constraint Without A Name In SQL Server
you can wrap reserved words in square brackets to avoid these kinds of errors:
dbo.TableName.[Date]
Actually you have to Do Like below Example, which will help to Solve the Issue...
drop table ABC_table
create table ABC_table
(
names varchar(20),
age int
)
ALTER TABLE ABC_table
ADD CONSTRAINT MyConstraintName
DEFAULT 'This is not NULL' FOR names
insert into ABC(age) values(10)
select * from ABC
I use the stored procedure below to update the defaults on a column.
It automatically removes any prior defaults on the column, before adding the new default.
Examples of usage:
-- Update default to be a date.
exec [dbo].[AlterDefaultForColumn] '[dbo].[TableName]','Column','getdate()';
-- Update default to be a number.
exec [dbo].[AlterDefaultForColumn] '[dbo].[TableName]','Column,'6';
-- Update default to be a string. Note extra quotes, as this is not a function.
exec [dbo].[AlterDefaultForColumn] '[dbo].[TableName]','Column','''MyString''';
Stored procedure:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- Sample function calls:
--exec [dbo].[AlterDefaultForColumn] '[dbo].[TableName]','ColumnName','getdate()';
--exec [dbol].[AlterDefaultForColumn] '[dbo].[TableName]','Column,'6';
--exec [dbo].[AlterDefaultForColumn] '[dbo].[TableName]','Column','''MyString''';
create PROCEDURE [dbo].[ColumnDefaultUpdate]
(
-- Table name, including schema, e.g. '[dbo].[TableName]'
#TABLE_NAME VARCHAR(100),
-- Column name, e.g. 'ColumnName'.
#COLUMN_NAME VARCHAR(100),
-- New default, e.g. '''MyDefault''' or 'getdate()'
-- Note that if you want to set it to a string constant, the contents
-- must be surrounded by extra quotes, e.g. '''MyConstant''' not 'MyConstant'
#NEW_DEFAULT VARCHAR(100)
)
AS
BEGIN
-- Trim angle brackets so things work even if they are included.
set #COLUMN_NAME = REPLACE(#COLUMN_NAME, '[', '')
set #COLUMN_NAME = REPLACE(#COLUMN_NAME, ']', '')
print 'Table name: ' + #TABLE_NAME;
print 'Column name: ' + #COLUMN_NAME;
DECLARE #ObjectName NVARCHAR(100)
SELECT #ObjectName = OBJECT_NAME([default_object_id]) FROM SYS.COLUMNS
WHERE [object_id] = OBJECT_ID(#TABLE_NAME) AND [name] = #COLUMN_NAME;
IF #ObjectName <> ''
begin
print 'Removed default: ' + #ObjectName;
--print('ALTER TABLE ' + #TABLE_NAME + ' DROP CONSTRAINT ' + #ObjectName)
EXEC('ALTER TABLE ' + #TABLE_NAME + ' DROP CONSTRAINT ' + #ObjectName)
end
EXEC('ALTER TABLE ' + #TABLE_NAME + ' ADD DEFAULT (' + #NEW_DEFAULT + ') FOR ' + #COLUMN_NAME)
--print('ALTER TABLE ' + #TABLE_NAME + ' ADD DEFAULT (' + #NEW_DEFAULT + ') FOR ' + #COLUMN_NAME)
print 'Added default of: ' + #NEW_DEFAULT;
END
Errors this stored procedure eliminates
If you attempt to add a default to a column when one already exists, you will get the following error (something you will never see if using this stored proc):
-- Using the stored procedure eliminates this error:
Msg 1781, Level 16, State 1, Line 1
Column already has a DEFAULT bound to it.
Msg 1750, Level 16, State 0, Line 1
Could not create constraint. See previous errors.
I confirm like the comment from JohnH, never use column types in the your object names!
It's confusing. And use brackets if possible.
Try this:
ALTER TABLE [TableName]
ADD DEFAULT (getutcdate()) FOR [Date];
You're specifying the table name twice. The ALTER TABLE part names the table.
Try:
Alter table TableName
alter column [Date] default getutcdate()
alter table TableName
drop constraint DF_TableName_WhenEntered
alter table TableName
add constraint DF_TableName_WhenEntered
default getutcdate() for WhenEntered

Resources