Dynamic SQL runtime column type - sql-server

Some of you may think I am doing the worst thing ever to a stored procedure but it's just a experiment at this time, this is what I am doing,
CREATE procedure [dbo].[Flags_Update]
(
#UserID nvarchar(255),
#CategoryID INT,
#ProductID INT,
#PropertyName nvarchar(255),
#PropertyValue nvarchar(max)
)
AS
DECLARE #sql nvarchar(500);
SET #sql = 'UPDATE Flags SET ' + #PropertyName + ' = ' + #PropertyValue + ' WHERE Flags Flags.CategoryID =' + #CategoryID + ' AND Flags.ProductID ='+ #ProductID;
EXEC(#sql);
IF (##ROWCOUNT=0)
BEGIN
SET #sql = 'INSERT INTO Flags(UserID, CategoryID, ProductID, '+ #PropertyName + ') VALUES(' + #UserID + ', ' + #CategoryID + ', ' + #ProductID + ', ' + #PropertyValue + ')';
EXEC(#sql);
END
GO
When executing I am getting this error,
Conversion failed when converting the nvarchar value 'UPDATE Flags SET
IsRelased = 1 WHERE Flags Flags.CategoryID =' to data type int.
I know the error is coming up because in procedure propertyName is nvarchar(255) when column type is INT, how can I overcome this error ?
Please note that some property column will be nvarchar and some will be INT
EDIT
I did a clever thing and decided to have each property column have nvarchar(255) as datatype but I am still getting this error.
EDIT 2
Casting as suggested by Martin below but getting this error now,
An expression of non-boolean type specified in a context where a
condition is expected, near 'Flags'

This is occurring because some of your parameters in the SET #sql statement are INT values.
Try CASTing (or CONVERTing) the INT fields to NVARCHARs. You will need to do this throughout your code where you concatenate text and numbers.
SET #sql = 'UPDATE Flags SET ' + #PropertyName + ' = ' + #PropertyValue + ' WHERE Flags Flags.CategoryID =' + CAST(#CategoryID AS NVARCHAR) + ' AND Flags.ProductID ='+ CAST(#ProductID AS NVARCHAR);
Note that I have changed + #CategoryID + to + CAST(#CategoryID AS NVARCHAR) +, and so on.

Related

Error while using variable declaration Incorrect syntax near '+#TABLENAME1+'

DECLARE #SQLSTRING VARCHAR(1500);
DECLARE #TABLENAME1 VARCHAR(30)='NOV19_COMBINE'
---------------TABLE CREATION WITH FILE NAME--------------------------
SET #SQLSTRING = 'SELECT
CONVERT(VARCHAR('+ cast((select max(len(EMAIL)) from '+#TABLENAME1+' ) as VARCHAR(50))+'), EMAIL ) AS EMAIL,
IDENTITY (INT,1,1) AS RECORDID
INTO FOI_'+#TABLENAME1+'_CONV
FROM '+#TABLENAME1+' A'
PRINT #SQLSTRING
Error:
Msg 102, Level 15, State 1, Line 8
Incorrect syntax near '+#TABLENAME1+'.
You have an issue here:
CONVERT(VARCHAR('+ cast((select max(len(EMAIL)) from ' + #TABLENAME1 + ' ) as VARCHAR(50))+')
where you are trying to select from a table defined in #TABLENAME1. That also needs to be part of your dynamic SQL.
However you have another issue with your convert(varchar( code in that you cannot use a variable as as the length to varchar(). I suggest using varchar(max) because that only uses the storage required.
I have also made your dynamic SQL safe from injection with the use of QUOTENAME which I recommend you use in future.
Fixed version:
DECLARE #SQLSTRING VARCHAR(1500);
DECLARE #TABLENAME1 VARCHAR(30) = 'NOV19_COMBINE'
---------------TABLE CREATION WITH FILE NAME--------------------------
SET #SQLSTRING = 'SELECT CONVERT(VARCHAR(max), EMAIL) AS EMAIL, IDENTITY (INT,1,1) AS RECORDID INTO '
+ QUOTENAME('FOI_' + #TABLENAME1 + '_CONV') + ' FROM '
+ QUOTENAME(#TABLENAME1) + ' A'
PRINT #SQLSTRING
There is no reason I can think of to do it this way, but as an academic exercise, if one really needed the exact length of the EMAIL column then one would use the following query:
declare #SQLSTRING nvarchar(max), #TABLENAME1 VARCHAR(30) = 'NOV19_COMBINE', #EMAILLENGTH int
SET #SQLSTRING = 'SELECT #Length = max(len(EMAIL)) from ' + QUOTENAME(#TABLENAME1)
EXECUTE sp_executesql #SQLSTRING, N'#Length int OUTPUT', #Length = #EMAILLENGTH OUTPUT
SET #SQLSTRING = 'SELECT CONVERT(VARCHAR(' + convert(varchar(4),#EMAILLENGTH) + '), EMAIL) AS EMAIL'
+ ', IDENTITY (INT,1,1) AS RECORDID'
+ ' INTO ' + QUOTENAME('FOI_' + #TABLENAME1 + '_CONV')
+ ' FROM ' + QUOTENAME(#TABLENAME1) + ' A'
PRINT #SQLSTRING
This requires 2 sections of dynamic SQL, the first to find the length of the EMAIL column, which is then used to built the dynamic SQL for the actual query.

Conversion failed when converting varchar into INT

I know there are a lot of questions asked like this, but I have tried almost all of the solution, but still can't get that one piece of code to work :( Here's what I'm doing - I'm trying to find the number of rows in a table so that I can use that as a counter to loop and delete rows.
#rc is INT,
#tbname is varchar (500)
and #id is also INT.
This is my query:
set #rc='select count(*) from dbo.[' + #tbname + '] where id = ' + #id
I have also tried these:
set #rc='select cast(count(*) as varchar) from dbo.[' + #tbname + '] where id = ' + #id
and
set #rc='select count(*) from dbo.[' + #tbname + '] where id = ' + cast(#id as varchar)
And a few more permutation of placing cast here and there as well. I also tried changing the declaration of #rc as varchar, still get the same error.
Use sp_executesql in this case,
DECLARE #retval int
DECLARE #sSQL nvarchar(500);
DECLARE #ParmDefinition nvarchar(500);
DECLARE #rc INT
,#str NVARCHAR(MAX)
,#tbname NVARCHAR(500) = 'Table1'
,#id int
set #str='select #rcOut = count(*) from dbo.[' + #tbname + '] where id = ' + CAST(#id as NVARCHAR)
EXEC sp_executesql #str, N'#rcOut int OUTPUT',#rcOut = #rc OUTPUT;
SELECT #rc;

dynamic sql in stored procedure with column name as input parameter

I have this stored procedure that accept a comlumn name as inptu parameter. The SELECT statement will select a column according to input parameter
create procedure getColumn (#whichColumn varchar)
as
begin
declare #sql nvarchar(max)
set #sql = 'SELECT [' + #whichColumn + ']'
+ ' FROM myTable'
+ ' where ['+ #whichColumn + '] is not null'
+ ' and [' + #whichColumn + '] != '''' ' ;
exec sp_executesql #sql
end
When I execute this stored procedure,
exec getColumn 'Apple';
the error says "Invalid column name 'A' " .
I cannot see why it only gets the first character of the input
Check out your parameter declaration:
#whichColumn varchar
From MSDN:
When n is not specified in a data definition or variable declaration
statement, the default length is 1.
So that's a single-letter varchar. Try to specify a size:
#whichColumn varchar(50)
Or even better, use the system-defined type for object names:
#whichColumn sysname
create procedure getColumn (#whichColumn nvarchar(128)) --<-- Maximum column name lenght
as
begin
declare #sql nvarchar(max);
set #sql = N'SELECT ' + QUOTENAME(#whichColumn)+ N' FROM myTable'
+ N' where '+ QUOTENAME(#whichColumn) + N' is not null'
+ N' and ' + QUOTENAME(#whichColumn) + N' != '''' ' ;
exec sp_executesql #sql
end
On a side note Using square brackets in you concatinating string isnt the same as using QUOTENAME function.
Change this line
create procedure getClumn (#whichColumn varchar)
to
create procedure getClumn (#whichColumn varchar(max))
because if you are not assign size of varchar at that time it consider only one character so it get only one character A and generate error.

use table name as parameter in sql function

I want create function, which use table name as parameter. As I search I need use dynamic sql. I try such code:
CREATE FUNCTION get_column_id
(
#TableName VARCHAR(30),
#ColumnName VARCHAR(30),
)
RETURNS int
AS
BEGIN
IF EXISTS
(
DECLARE #SQL VARCHAR(50)
SET #sql = 'SELECT' + #ColumnName + 'FROM' + #TableName + 'WHERE #ColumnName = #ColumnNameValue';
EXEC(#sql)
)
BEGIN
But get errors. Is where any way to procceed this?
I try use dynamic sql in such way
DECLARE #SQL VARCHAR(50)
SET #SQL = 'SELECT' + #ColumnName + 'FROM' + #Table + 'WHERE #ColumnName = #ColumnNameValue'
EXEC(#SQL)
DECLARE #TableName table (Name VARCHAR(30))
INSERT INTO #TableName VALUES (#SQL)
IF EXISTS
(SELECT Name FROM #TableName WHERE Name = #ColumnNameValue)
But get Invalid use of a side-effecting operator 'EXECUTE STRING' within a function.
Does anyone knows how bypass this constraint?
The error is the concatenation of string which lacks space in between,
SET #sql = 'SELECT ' + #ColumnName + ' FROM ' + #TableName + ' WHERE ' + #ColumnName + ' = ' + #ColumnNameValue;
-- ^ SPACE HERE ^ ^ ^ and here
if for instance the data type of the column is string, you need to wrap the value with single quotes,
SET #sql = 'SELECT ' + #ColumnName + ' FROM ' + #TableName + ' WHERE ' + #ColumnName + ' = ''' + #ColumnNameValue + '''';
UPDATE 1
You also need to declare the parameter #ColumnNameValue, eg
CREATE FUNCTION get_column_id
(
#TableName VARCHAR(30),
#ColumnName VARCHAR(30),
#ColumnNameValue VARCHAR(30)
)
A UDF (user defined function) in Sql Server must be deterministic. Beside your syntax errors you won't be able to accomplish your task.
if you check this article on MSDN:
http://msdn.microsoft.com/en-us/library/ms178091.aspx
You can see the citation below:
Deterministic functions always return the same result any time they are called
with a specific set of input values and given the same state of the database.
Nondeterministic functions may return different results each time they are
called with a specific set of input values even if the database state that
they access remains the same.

SQL 2012 - SearchAllTables for datetime Stored procedure

I'm trying to create a stored procedure that will search all user created tables of a database for a search string.
I found this stored procedure that I'd like to start off with and build on.
http://vyaskn.tripod.com/search_all_columns_in_all_tables.htm
The only problem is entering a datetime into the search will always return nothing.
How can I modify this to search for dates as well?
Lines of interest:
CREATE PROC SearchAllTables
#SearchStr nvarchar(100)
AS
....
SET #SearchStr2 = CASE WHEN ISDATE(#SearchStr)=0
THEN QUOTENAME('%' + #SearchStr + '%','''')
ELSE #SearchStr END
....
--Here's where the comparison is made. This comparison works for string and numeric types but not datetime
DECLARE #sql nvarchar(max)
IF ISDATE(#SearchStr) = 0
BEGIN
SET #sql = 'INSERT INTO #Results SELECT ''' + #TableName + '.' + #ColumnName + ''', LEFT(' + #ColumnName + ', 3630)
FROM ' + #TableName + ' (NOLOCK) ' +
' WHERE ' + #ColumnName + ' LIKE ' + #SearchStr2
END
ELSE IF ISDATE(#SearchStr) = 1
BEGIN
SET #sql = 'INSERT INTO #Results SELECT ''' + #TableName + '.' + #ColumnName + ''', LEFT(' + #ColumnName + ', 3630)
FROM ' + #TableName + ' (NOLOCK) ' +
' WHERE DATEDIFF(day, CONVERT(datetime, '+ #ColumnName + ', 103), ' + #SearchStr+ ') = 0'
END
PRINT #sql
EXEC sp_ExecuteSQL #sql
GO
I get a conversion error. I need this stored procedure to work with all 3 types of data string, numeric, and date.
Conversion failed when converting date and/or time from character string.
Thank you
your date field is a datetime?
you should traet it like this:
declare #SearchStr datetime
set #SearchStr = convert(datetime, '2012-09-10', 103) –- dd/mm/yyyy
and the where part like this:
'WHERE Datediff(day, CONVERT(datetime, '+ #ColumnName + ', 103), ' + #SearchStr+') = 0'
I think this should work
If the search string is a date then you have to do an explicit conversion. Otherwise string will not match with datetime.
Try something like this.
SET #SearchStr2 = CASE WHEN ISDATE(#SearchStr)=1
THEN CONVERT(datetime,#SearchStr,103)
ELSE QUOTENAME('%' + #SearchStr + '%','''') END
Hope this will help you.
ElVieejo's answer was correct but for it to finally work I also needed to SET #ColumnName conditionally (depending IF ISDATE(#SearchStr) ). If #SearchStr is a date, the inner query of SET #ColumnName had to EXCLUDE all types except the 'datetime' under "DATA_TYPE IN ('datetime')".

Resources