use table name as parameter in sql function - sql-server

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.

Related

How do i insert or update a record based on data whicha has a apostohphe in a dynamic sql?

Here the #Data has a value with apostophe(')s . how do i update or insert a data based on the data value which is having apostophe in a dynamic sql
suppose #data has one value abc and another value abc's it throwing error for the second one
SET #SQL = ' Update '+ #ProcessCode + '_abc SET IS_IGNORING = 1 where Column_Name = '''+ #Column_Name +''' and [DATA] = ''' + #Data + ''' and Table_name = '''+ #Table_Name + ''''
Generally what i found is a manual process of adding one more apostophe but i am not really sure how to use that in a dynamic sql where not all data in the table is same, few of the data records has got this type of apostophe(')
Parameterized your query using sp_executesql
Example:
SET #SQL = 'Update ' + #ProcessCode + '_abc '
+ 'SET IS_IGNORING = 1 '
+ 'where Column_Name = #Column_Name '
+ 'and [DATA] = #Data '
+ 'and Table_name = #Table_Name '
EXEC sp_executesql #SQL,
N'#Column_Name varchar(100), #Data varchar(100), #Table_Name varchar(100)',
#Column_Name, #Data, #Table_Name
Do read up more on dynamic query and SQL Injection
You might find convenient to use parameterized queries, so you can replace static values with placeholders and then bind values to those placeholders before executing the query. It has certain advantages like better performance and helps to avoid SQL-injection attacks.
More info here: https://techcommunity.microsoft.com/t5/sql-server-blog/how-and-why-to-use-parameterized-queries/ba-p/383483

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.

Stored Procedure: Passing a parameter when using dynamic SQL for pivoting data

As the title suggests, I'm trying use dynamic SQL to get column names for a pivoted table - however, I also want to be able to pass a parameter to a variable called #assessments, but I just can't seem to get it to work. Below is the code I'm using, would appreciate if anyone could take a look and let me know where I'm going wrong. Thank you
create PROCEDURE [dbo].[spTestExamResults]
AS
BEGIN
DECLARE #SQL as NVARCHAR(MAX)
DECLARE #ColumnName as NVARCHAR(MAX)
DECLARE #assessment as NVARCHAR(50)
SET NOCOUNT ON;
--Get distinct values from pivot source
SELECT #ColumnName = ISNULL(#ColumnName + ',','') + QUOTENAME(subjectname)
From (SELECT DISTINCT SubjectName From qryPupilNCTest) as p order by p.Subjectname
SET #SQL =
'select pupil,PupilName, year' + #ColumnName + '
FROM qrypupilnctest
Where assessment in (' + #assessment + ')
PIVOT (MAX(grade) for subjectname in (' +#ColumnName + ')) piv'
EXEC (#SQL)
END
In your case, #assessment is the local variable with out any initialization and handled in the operation. So it always have empty value only and you won't get any result from the stored procedure.
As per your post title, you can alter the stored procedure and pass the #assessment as parameter, so the WHERE assessment IN ( will have some valid data and you will receive some valid result.
ALTER PROCEDURE [dbo].[spTestExamResults]
(
#assessment NVARCHAR(50)
)
AS
BEGIN
DECLARE #SQL AS NVARCHAR(MAX)
DECLARE #ColumnName AS NVARCHAR(MAX)
-- DECLARE #assessment as NVARCHAR(50) -- Remove the #assessment from the local variable
SET NOCOUNT ON;
--Get distinct values from pivot source
SELECT #ColumnName = ISNULL(#ColumnName + ',','') + QUOTENAME(subjectname)
FROM (SELECT DISTINCT SubjectName FROM qryPupilNCTest) AS p
ORDER BY p.Subjectname
SET #SQL = 'SELECT pupil, PupilName, year' + #ColumnName + '
FROM qrypupilnctest
WHERE assessment IN (' + #assessment + ')
PIVOT (MAX(grade) FOR subjectname IN (' + #ColumnName + ')) piv'
EXEC (#SQL)
END
So the execution call will be:
EXEC [dbo].[spTestExamResults] 'paramvalue1, paramvalue2'

Dynamic SQL runtime column type

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.

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.

Resources