I am building dynamic SQL statements. I am checking for null values, and if the value is not null, putting single quotes around the parameter value. In the below #TEST_GU is a string parameter.
BEGIN TRAN
DECLARE #SQL nvarchar(max)
SELECT #SQL = 'UPDATE [THIS IS A TABLE]
SET [TEST_GU]=' + '''' + ISNULL(#TEST_GU,'') + ''''+',
+ ' SELECT [TEST_GU] FROM
[THIS IS A TABLE]
WHERE [TEST_GU] =' + '''' + ISNULL(#TEST_GU,'') + '''' +''
PRINT LEN(#SQL)
EXEC (#SQL)
COMMIT
This wont work because if its null, it ends up putting quotes around the empty value, so makes the whole statement become unformatted. So my question is, in the above format, is it possible to check for null values, if null use the second argument of the ISNULL method (in this case, an empty ''). If it is not null, put the parameter value in single quotes.
Just put the quotes inside the isnull():
SELECT #SQL = 'UPDATE [THIS IS A TABLE]
SET [TEST_GU]=' + '''' + ISNULL(''''+#TEST_GU+'''','') + ''''+',
+ ' SELECT [TEST_GU] FROM
[THIS IS A TABLE]
The concatenation will return NULL if the value is NULL, so it still does what you want.
Related
When I try to execute the following:
DECLARE #sqlText nvarchar(1000);
SET #sqlText = N'SELECT TOP ' + CAST((:intValue) AS VARCHAR(20)) + 't_stamp, PART_NUM, ' + :Column + ' FROM dbo.press_7_recipes_log WHERE PART_NUM = ' + CAST(:text AS VARCHAR(20))
Exec (#sqlText)
I am getting the following
error:com.microsoft.sqlserver.jdbc.SQLServerException: Conversion failed when converting the varchar value '43302001-8' to data type int.
Any help would be greatly appreciated, not sure what else is required here.
:intValue is of type int4
:text is of type string
:Column is of type string (This is pulling a specified column from the database and why I think this needed to be a dynamic query)
Tried multiple attempts at googling the issue and changing the command with the same outcome. If I change the PART_NUM in the where to a column that is of type int the code works fine, any string related column does not.
The problem is that after your preparation the query becomes:
SELECT TOP 666 t_stamp, PART_NUM, ANOTHER_COLUMN FROM dbo.press_7_recipes_log WHERE PART_NUM = 43302001-8
And since 43302001-8 is an INTEGER=43301993, SQL Server converts PART_NUM column to INT, which doesn't work since it probably contains non-integers.
You need to change your dynamic query to this me thinks:
DECLARE #sqlText nvarchar(1000);
SET #sqlText = N'SELECT TOP ' + CAST((:intValue) AS VARCHAR(20)) + 't_stamp, PART_NUM, ' + :Column + ' FROM dbo.press_7_recipes_log WHERE PART_NUM = ''' + REPLACE(CAST(:text AS VARCHAR(20)), '''', '''''') + ''''
Exec (#sqlText)
This will change WHERE to: PART_NUM = '43302001-8'
But as others noticed, you have a lot of possibilities for SQL Injections here. So i'd probably get rid of this code and rewrite it to avoid dynamic SQL
I am trying to call an sql function accepting a nullable parameter - from a dynamic SQL statement.
Creating the dynamic statement is difficult because when the parameter value is 'NULL' the concatentation causes the whole statement to be empty. I have the following:
SET dynamicQuery =
'select * from [qlik].udf_getStatistic( ''' + #myParameter + ''' )'
The sample above is inside a stored procedure to which #myParameter is passed. It may be null, or a string value. Clearly, when it is a string it needs to be enclosed in quotes, but when it is null it must not be enclosed in quotes. As follows:
select * from [qlik].udf_getStatistic( 'Heights' )
select * from [qlik].udf_getStatistic( NULL )
The question is equally applicable to calling a stored procedure accepting a nullable parameter from dynamic SQL.
The examples are from SQL Server.
Just escape the NULL value with an explicit literal NULL, making sure that the quotes are only included when the value is not NULL.
DECLARE #myParameter VARCHAR(10) = 'ABC'
DECLARE #dynamicQuery VARCHAR(MAX)
SET #dynamicQuery =
'select * from [qlik].udf_getStatistic(' + ISNULL('''' + #myParameter + '''', 'NULL') + ')'
SELECT #dynamicQuery -- select * from [qlik].udf_getStatistic('ABC')
SET #myParameter = NULL
SET #dynamicQuery =
'select * from [qlik].udf_getStatistic(' + ISNULL('''' + #myParameter + '''', 'NULL') + ')'
SELECT #dynamicQuery -- select * from [qlik].udf_getStatistic(NULL)
You might want to escape additional single quotes that might be on your variable, replacing them with double single quotes, so it doesn't break your dynamic build.
The answer is actually different between stored procedures and functions.
From Books On Line or whatever they call it this month (Scroll down a ways):
When a parameter of the function has a default value, the keyword DEFAULT must be specified when the function is called to retrieve the default value. This behavior is different from using parameters with default values in stored procedures in which omitting the parameter also implies the default value. However, the DEFAULT keyword is not required when invoking a scalar function by using the EXECUTE statement.
So for a proc, when you want to pass a NULL parameter, you can just not pass it. For a function, though, you have to tell it to use the DEFAULT value explicitly. Either way, you do not pass it an explicit NULL. Luckily for your dynamic SQL, though, the explicit DEFAULT also works with a stored procedure. In both cases, in order to make sure that the parameters you are passing get assigned correctly, you want to use explicit parameter names in your call.
Let's use this function definition:
CREATE FUNCTION (or procedure) [qlik].udf_getStatistic (
#param1 integer = 0,
#param2 varchar(100) = 'foo'
) AS ...
Both parameters are optional. Since this is a function, this call will throw an insufficient number of parameters error:
select * from [qlik].udf_getStatistic( 'Heights' );
If it were a procedure call, it would throw a cannot convert value 'Heights' to data type integer because it will apply the only parameter value passed to the first parameter it encounters, which is expecting an integer. In both cases, you get what you want this way:
select * from [qlik].udf_getStatistic( #param1 = DEFAULT, #param2 = 'Heights' );
Which brings us to your dynamic SQL. Add your parameter name(s) to the static text, then use COALESCE (or CASE if you like) to decide whether to pass an explicit value, or the DEFAULT call.
DECLARE #myParameter1 VARCHAR(100) = 'foo',
#myParameter2 INTEGER,
#SQL NVARCHAR(MAX);
SET #SQL =
'select
*
from [qlik].udf_getStatistic(
#param1 = ''' + COALESCE(#myParameter1, 'DEFAULT') + ''',
#param2 = ' + COALESCE(CAST(#myParameter2 AS VARCHAR(30)),'DEFAULT') + ' );';
SELECT #SQL;
Result:
select * from [qlik].udf_getStatistic( #param1 = 'foo', #param2 = DEFAULT );
From my understanding, I try this on SQL Server 2012,
CREATE PROCEDURE ToNullProc
(#i VARCHAR(20))
AS
BEGIN
PRINT 'you entered ' + #i
END
CREATE FUNCTION ToNullFun
(#i VARCHAR(20))
RETURNS #table TABLE (i VARCHAR(20))
AS
BEGIN
INSERT INTO #table
SELECT ('You entered ' + #i) a
RETURN
END
DECLARE #j VARCHAR(20) = 'Hi',
#QueryFun NVARCHAR(50) = N'',
#QueryProd NVARCHAR(50) = N''
IF #j IS NOT NULL
BEGIN
SET #QueryFun = N'select * from ToNullFun ('''+#j+''')'
SET #QueryProd = N'exec ToNullProc '''+#j+''''
END
ELSE BEGIN
SET #QueryFun = N'select * from ToNullFun ('+#j+')'
SET #QueryProd = N'exec ToNullProc '+#j+''
END
PRINT #queryfun
PRINT #queryprod
EXEC sp_executesql #queryfun
EXEC sp_executesql #queryprod
update for dynamic procedure and dynamic function :
create table #temp (Num int identity (1,1), NullVal int)
insert into #temp (NullVal) values (1),(null),(3)
alter proc ToNullProc (
#Operator varchar (max), #NullVal varchar (max)
) as
begin
declare #Query nvarchar (max) = N'select * from #temp where NullVal ' +
#Operator + #NullVal
-- print #query + ' ToNullProc print '
exec sp_executesql #query -- Here we run the select query from Proc
end
create function ToNullFun (
#Operator varchar (max), #NullVal varchar (max)
)
returns nvarchar (max)
as
begin
declare #Query nvarchar (max)
set #Query = N'select * from #temp where NullVal ' + #Operator + #NullVal
/*
I try to into to Table variable by using ITVF,
'insert into #table exec sp_executesql #query'.
But this type of insert is not allowed in ITVF.
*/
return #query
end
declare #NullVal varchar (max) = '1'
, #QueryFun nvarchar (max) = N''
, #QueryProd nvarchar (max) = N''
declare #FunResultTalbe table (
Query nvarchar (100)
) /* To store the result Funtion */
if #NullVal is not null
begin
set #QueryFun = N'select dbo.ToNullFun ('' = '','''+#NullVal+''')'
set #QueryProd = N'exec ToNullProc '' = '','''+#NullVal+''''
end
else begin
set #QueryFun = N'select dbo.ToNullFun ('' is null '','''')'
set #QueryProd = N'exec ToNullProc '' is null '','''''
end
print #queryfun + ' At start'
print #queryprod + ' At start'
exec sp_executesql #queryprod -- It calls Proc
insert into #FunResultTalbe
exec sp_executesql #queryfun -- It calls the Function and insert the query into the table.
set #QueryFun = (select top 1 * from #FunResultTalbe) -- Here we get the query from the table.
print #queryfun
exec sp_executesql #queryfun -- Here we run the select query. Which is dynamic
Result sets
-- Result of Procedure
Num NullVal
1 1
-- Result of Function
Num NullVal
1 1
Let me know, what did you got.
I'm trying to figure out why my where clause is returning all rows.
I'm querying a column that contains csv's using a variable that also contains csv's. I've built a stored function to split the variable on csv and return a table with one row that contains what I'd like to have on the right side of the LIKE operator.
Example:
The stored function:
ALTER Function [dbo].[storedFunction]
(#Fields VARCHAR(MAX),
#Field_Name VARCHAR(MAX) = '')
RETURN #Tbl_Fields Table (FIELD Varchar(max))
AS
BEGIN
DECLARE #FIELD varchar(max) = REPLACE(#Fields, ',', '%''' + ' AND ' +
#Field_Name + ' Like ' + '''%');
INSERT INTO #Tbl_Fields
SELECT '''%' + #FIELD + '%'''
RETURN
END
Using the stored function:
BEGIN
DECLARE #variable varchar(max) = 'variable1, variable3';
END
SELECT field
FROM storedFunction(#variable, 'main_csv_field');
returns '%variable1%' AND main_csv_field Like '%variable3%'
My simplified query:
BEGIN
DECLARE #variable varchar(max) = 'variable1, variable3';
END
SELECT main_csv_field
FROM table
WHERE (main_csv_field LIKE (SELECT field
FROM storedFunction(#variable, 'main_csv_field');
returns
variable1,variable2,variable3,variable4,...
variable2,variable4,...
variable1,variable3,...
My problem is this last query returns all of the rows in the table regardless of value matching. Were I to copy and paste the value returned from the stored function I would get the data that I need.
How/what is the difference here?
Thanks to #Obie and #AllanS.Hansen I knew where to start looking to fix this. Its pretty rough, but I wanted to post a solution before I got too far down the rabbit hole:
DECLARE variable1 varchar(max) = '' --around 9 passed from code
DECLARE #query nvarchar(max);
DECLARE #column_list varchar(max) = 'column1, column2, etc'
--one of each of the tests per variable passed from code
DECLARE #variable1_test nvarchar(max) = (SELECT CASE WHEN #variable = '' THEN '%' ELSE (SELECT * from dbo.stored_function(#variable, 'column_name')) END);
END;
SET #query = ' SELECT ' + #column_list + '
FROM table_name
WHERE variable LIKE ''' + #variable_test + ''' '
EXECUTE sp_executesql #query;
print(#query); --This is just to see the resulting query, which helped me a ton
Exciting! Now I have to test it.
We have a stored procedure built using dynamic sql where our application passes in some column names. Occasionally blank or null values are passed through for the column name. In these cases the sp needs to return a null value for the column. I've tried various ways of handling this but whatever I do I seem to get the error below:
An object or column name is missing or empty. For SELECT INTO statements, verify each column has a name. For other statements, look for empty alias names. Aliases defined as "" or [] are not allowed. Change the alias to a valid name.
Here is an example query with case when trying to handle null column names in the #Col2 param:
DECLARE
#Col1 varchar(32) = 'name',
#Col2 varchar(32) = '',
#sqlCommand nvarchar(MAX) = ''
SET #sqlCommand = #sqlCommand + N'
SELECT ' + quotename(#Col1) + ' AS ' + quotename(#Col1) + ',
CASE WHEN ' + quotename(#Col2) + ' IS NULL OR ' + quotename(#Col2) + ' = ''''
THEN NULL
ELSE ' + quotename(#Col2) + '
END AS Col2
FROM sys.columns c '
EXECUTE sp_executesql #sqlCommand
Solution
DECLARE
#Col1 varchar(32) = 'name',
#Col2 varchar(32) = '',
#sqlCommand nvarchar(MAX) = ''
SET #sqlCommand = #sqlCommand + N'
SELECT ' + quotename(#Col1) + ' AS ' + quotename(#Col1) + ',' +
CASE WHEN #Col2 IS NULL OR #Col2 = ''
THEN 'NULL '
ELSE quotename(#Col2)
END + ' AS Col2
FROM sys.columns c '
--print #sqlCommand
EXECUTE sp_executesql #sqlCommand
Notes
When you have an issue with Dynamic SQL, try using the Print statement to output the generated command to SSMS (or if you're not using SSMS, find some other way to pull back the generated SQL so you can see what's going on.
Doing this with your original code shows that the statement generated was:
SELECT [name] AS [name],
CASE WHEN [] IS NULL OR [] = ''
THEN NULL
ELSE []
END AS Col2
FROM sys.columns c
... which you can probably see the issue with.
The problem was that you got confused between the SQL you were using to generate the Dynamic SQL, and the SQL required to be part of the Dynamic SQL statement being returned.
I have a Microsoft SQL Server trigger that updates a remote database with new values when the local database is updated. Everything works fine, and I tested the script and it updates fine, unless there is a null value.
The code is below:
DECLARE #TSQL nvarchar(4000);
SELECT #TSQL =
'UPDATE
OPENQUERY(TEST,''SELECT * FROM test_db WHERE id = ' + convert(VARCHAR(MAX), #id) +''')
SET
parent_id = ' + convert(VARCHAR(MAX), #parent_id) + ', user_id = ' + convert(VARCHAR(MAX), #user_id) + ', item_id = ' + convert(VARCHAR(MAX), #item_id) + ''
EXEC (#TSQL)
Everything works well if all the fields have values, but if one column is null, then the query doesn't update the row at all, no errors thrown. I tried to use COALESCE() to change the null variables to empty strings, and it will then update the row, but all the null columns become 0's and I want them to stay as NULL values. All the columns in both database allow null values and default to null so I'm not sure why I cannot update the database.
Any help would be nice, thanks!
Try this. Use ISNULL and if the value is null, use 'NULL' in single quotes. When the string is concatenated together, it won't keep the quotes, so it would set it to a NULL value and not a string of 'NULL'.
DECLARE #TSQL nvarchar(4000);
SELECT #TSQL =
'UPDATE
OPENQUERY(TEST,''SELECT * FROM test_db WHERE id = ' + convert(VARCHAR(MAX), #id) +''')
SET
parent_id = ' + ISNULL(convert(VARCHAR(MAX), #parent_id), 'NULL') + ',
user_id = ' + ISNULL(convert(VARCHAR(MAX), #user_id), 'NULL') + ',
item_id = ' + ISNULL(convert(VARCHAR(MAX), #item_id), 'NULL') + ''
EXEC (#TSQL)