Dynamic SQL concatenation - sql-server-2008

Having an issue concatenating the following statement.
Basically I want the length column to add inches after but it will not run. I am going to create a function out of this in the future but unable to get past this step. What gives?
declare #column varchar(255)
declare #sql varchar(5000)
declare #additional varchar(500)
set #column = 'length'
set #additional = 'inches'
select #sql = 'select distinct ps.p_c_id, '
select #sql = #sql + #column + ' '+#additional+ ' ' + ' as value'
select #sql = #sql
select #sql = #sql + ' from dbo.Product ps
inner join dbo.ProductAttributes psa on psa.p_s_id = ps.p_s_id
where ps.p_c_id is not null and ' + #column + ' is not null'
exec (#sql)

You are concatenating, what i'm assuming is an int or float value to a string ' inches'...have to cast the "length" value as a varchar...
just select your #sql next time to see the resulting syntax and it should jump out at you. here is changes that should work
BTW...look at implementing EXEC sp_executesql ...makes dynamic sql less suseptable to injection by using parameters, etc... look up in Books OnLine
Sorry...eating Crow...sp_executesql does not protect from injection just improves performance in general...see article MSDN SQL Injection
declare #column varchar(255)
declare #sql varchar(5000)
declare #additional varchar(500)
set #column = 'psa.length'
set #additional = 'inches'
select #sql = 'select distinct ps.p_c_id, '
select #sql = #sql + 'CAST(' + #column + ' AS varchar(10)) + ' + ''' '+#additional+ ''' ' + ' as value'
select #sql = #sql
select #sql = #sql + ' from dbo.Product ps
inner join dbo.ProductAttributes psa on psa.p_s_id = ps.p_s_id
where ps.p_c_id is not null and ' + #column + ' is not null'
--select #sql AS [ExecutableSQL]
exec(#sql)

Your output is;
select distinct ps.p_c_id, length inches as value from dbo.Product ps
inner join dbo.ProductAttributes psa on psa.p_s_id = ps.p_s_id
where ps.p_c_id is not null and length is not null
So it looks like a missing , between length inches assuming you want both;
select #sql = #sql + #column + ','+ #additional+ ' ' + ' as value'

Related

SQL Server Execute update result sets from dynamic query writer

This link is where I found part of an answer to my problem.
SQL replace all NULLs
Simon posted
"Be a boss. Write something like:
select 'update ' + table_name + ' set [' + column_name + '] = '''' where [' + column_name + '] is null'
from tempdb.information_schema.columns
where table_name = 'YourTableName'
It'll spit out a big ol' query for you.
You're welcome"
But I would like to know if there a way to use the results set in a parameter and execute all of the update statements.
I tried something like this
DECLARE #sql2 AS NVARCHAR(MAX) = N'
SELECT ''UPDATE '' + table_name + '' SET ['' + column_name + ''] = '''''''' WHERE ['' + column_name + ''] IS NULL''
FROM tempdb.information_schema.columns
WHERE table_name = ''##tempF'''
EXEC sp_executesql #stmt = #sql2;
DECLARE #sql3 AS NVARCHAR(MAX);
SET #sql3 = (SELECT #sql2);
EXEC sp_executesql #stmt = #sql3;
but it two result sets like listed below:
UPDATE ##tempF SET [claimid] = '' WHERE [claimid] IS NULL
UPDATE ##tempF SET [hdr_status] = '' WHERE [hdr_status] IS NULL
UPDATE ##tempF SET [memid] = '' WHERE [memid] IS NULL
Many thanks to you all.
Cheers!
Tim
Like this
--initialize variables
DECLARE #UpdateColumns varchar(max) = ''
DECLARE #IsNullColumns varchar(max) = ''
SELECT
#UpdateColumns = #UpdateColumns + ',[' + COLUMN_NAME + '] = ISNULL([' + COLUMN_NAME + '],'''')',
#IsNullColumns = #IsNullColumns + ' OR [' + COLUMN_NAME + '] IS NULL'
FROM tempdb.information_schema.columns
WHERE table_name = '##tempF'
This should fill in the two variables with the following values:
#UpdateColumns = ',[claimid] = ISNULL([claimid],''''),[hdr_status] = ISNULL([hdr_status],''''),[memid] = ISNULL([memid],'''')'
#IsNullColumns = ' OR [claimid] IS NULL OR [hdr_status] IS NULL OR [memid] IS NULL'
Then you need to assemble it all (remember to remove the first characters of each of the variables (the STUFF function is great for that):
DECLARE #qry varchar(max) = 'UPDATE ##tempF SET '
+ STUFF(#UpdateColumns,1,1,'') + ' WHERE '
+ STUFF(#IsNullColumns,1,4,'') --the 4 in here is to get rid of ' OR ' (4 chars)
EXEC(#qry)

Dynamic SQL issue

I have a dynamic SQL which sits inside a stored procedure, but when I run the stored procedure I am not seeing any results. It is very odd, because when I strip out the SQL from the string, and just run it as an SQL Query I do get back results. I have tried getting the Dynamic SQL to print out so I could see what is going on, but this isn't working either. Therefore, I am at a loss to see what I am doing wrong, and would kindly ask if anyone can see what is wrong. Below is the query:
SELECT #SQL = #SQL + 'Select Production_Site, CSN, Target, Action, Fail '
SELECT #SQL = #SQL + 'From syn_products prod, '
SELECT #SQL = #SQL + '(select Production_Site, CSN, SUM([Target]) AS Target,SUM([Action]) AS Action,SUM([Fail]) AS Fail '
SELECT #SQL = #SQL + ' from '
SELECT #SQL = #SQL + ' ( '
SELECT #SQL = #SQL + ' select Production_Site, value, Period, YEAR, week, CSN '
SELECT #SQL = #SQL + ' from t_Pqe_Grocery '
SELECT #SQL = #SQL + ' unpivot ( '
SELECT #SQL = #SQL + ' value '
SELECT #SQL = #SQL + ' for col in (Grocery_Packaging_And_Coding, Grocery_Measurable, '
SELECT #SQL = #SQL + ' Grocery_Appearance, Grocery_Aroma, '
SELECT #SQL = #SQL + ' Grocery_Flavour, Grocery_Texture)) unp '
SELECT #SQL = #SQL + ' ) src '
SELECT #SQL = #SQL + ' pivot '
SELECT #SQL = #SQL + ' ( '
SELECT #SQL = #SQL + ' count(value) '
SELECT #SQL = #SQL + ' for value in ([Target], [Action], [Fail]) '
SELECT #SQL = #SQL + ' ) piv '
SELECT #SQL = #SQL + ' where Production_Site IN ( ''' + #Site + ''') AND YEAR BETWEEN ' + CONVERT(varchar(50),CONVERT(BIGINT,#ToYear))+ 'AND '+ CONVERT(varchar(50),CONVERT(BIGINT,#FromYear))+ 'AND Period BETWEEN ' + CONVERT(varchar(50),CONVERT(BIGINT,#ToPeriod))+ ' AND '+ CONVERT(varchar(50),CONVERT(BIGINT,#FromPeriod))+ 'AND Week BETWEEN ' + CONVERT(varchar(50),CONVERT(BIGINT,#ToWeek))+ ' AND '+CONVERT(varchar(50),CONVERT(BIGINT,#FromWeek))+ ' GROUP BY Production_Site CSN'
SELECT #SQL = #SQL + ' ) pit'
SELECT #SQL = #SQL + ' WHERE prod.pProductCode = pit.CSN AND prod.pPowerBrand = ''POW'''
EXECUTE(#SQL)
Sometimes formatting your query in a different way can help find any errors with your query. You were missing some spaces in your query string:
declare #sql varchar(max)
declare #Site varchar(10) = 'testSite'
declare #ToYear int = 2010
declare #FromYear int = 2012
declare #ToPeriod int = 45
declare #FromPeriod int = 56
declare #ToWeek int = 10
declare #FromWeek int = 1
SET #SQL =
'Select Production_Site, CSN, Target, Action, Fail
From syn_products prod
inner join
(
select Production_Site, CSN, SUM([Target]) AS Target,SUM([Action]) AS Action,SUM([Fail]) AS Fail
from
(
select Production_Site, value, Period, YEAR, week, CSN
from t_Pqe_Grocery
unpivot
(
value
for col in (Grocery_Packaging_And_Coding,
Grocery_Measurable, Grocery_Appearance,
Grocery_Aroma, Grocery_Flavour, Grocery_Texture)
) unp
) src
pivot
(
count(value)
for value in ([Target], [Action], [Fail])
) piv
where Production_Site IN ( ''' + #Site + ''')
AND YEAR BETWEEN ' + CONVERT(varchar(50),CONVERT(BIGINT,#ToYear))+ ' AND '+ CONVERT(varchar(50),CONVERT(BIGINT,#FromYear))
+ ' AND Period BETWEEN ' + CONVERT(varchar(50),CONVERT(BIGINT,#ToPeriod))+ ' AND '+ CONVERT(varchar(50),CONVERT(BIGINT,#FromPeriod))
+ ' AND Week BETWEEN ' + CONVERT(varchar(50),CONVERT(BIGINT,#ToWeek))+ ' AND '+CONVERT(varchar(50),CONVERT(BIGINT,#FromWeek))
+ ' GROUP BY Production_Site CSN
) pit
on prod.pProductCode = pit.CSN
where prod.pPowerBrand = ''POW'''
select #sql
This is now printing --- See SQL Fiddle with Demo -- I also changed the query to use ANSI join syntax instead of comma separated joins.
These are probably syntax errors:
... CONVERT(BIGINT,#ToYear))+ 'AND '+ ...
^--- no space
... #FromYear))+ 'AND Period BETWEEN ...
^---no space
... #FromPeriod))+ 'AND Week BETWEEN
^-- yet again no space
One of your variables is probably NULL. Concatenating a NULL value into your string will result in a NULL string. Both PRINT and EXECUTE when given NULL strings..
First, you need to set the #SQL parameter to an empty string or change the first line to set the value instead of concatenating it. Then, you may need to do some kind of checking to verify the parameters are NOT NULL and, if they are, either remove the criteria, or substitute something else:
DECLARE #SQL VARCHAR(MAX)
SELECT #SQL = ''
SELECT #SQL = #SQL + ... -- now build the SQL Statement
SELECT #SQL = #SQL + ' where Production_Site IN ( ''' + ISNULL(#Site, '') + ''' ... -- check for NULLs here
PRINT ISNULL(#SQL, 'NULL) -- this should now print something even if the SQL is NULL
Finally, beware of SQL injection attacks! Avoid concatenating parameters into a dynamic SQL statement like this. Instead, parameterize the dynamic SQL, and pass the parameters along with the EXECUTE statement.

tsql dynamic sql best approach

The dynamica query I have below works but wondering if what I have below can be optimized or if there is a better way of doing it.
I have a web form where the user enters a location and Date Collected. For the date collected, I have a From Date Collected and To Date Collected. The user an leave the To date collected blank in which case it will do anything greater than the From Date Collected.
Note how I am doing the IS NOT NULL and 1=1 below. Also wondering if a dynamic SQL is the best approach or if there is a simpler way of doing this.
DECLARE #sql varchar(max);
SET #sql = 'SELECT * from tblProgram WHERE 1=1'
IF (#Location IS NOT NULL)
BEGIN
SET #sql = #sql + ' AND Location = ' + #Location
END
IF (#FromDateCollected IS NOT NULL AND #ToDateCollected IS NOT NULL)
BEGIN
SET #sql = #sql + ' AND pw.DateCollected >= ' + QUOTENAME(convert(varchar, #FromDateCollected,101),'''')
+ ' AND pw.DateCollected <= ' + QUOTENAME(convert(varchar, #ToDateCollected,101),'''')
END
ELSE IF (#FromDateCollected IS NOT NULL AND #ToDateCollected IS NULL)
BEGIN
SET #sql = #sql + ' AND pw.DateCollected >= ' + QUOTENAME(convert(varchar, #FromDateCollected,101),'''')
END
exec(#sql)
Well you can do as ta.speot.is comments use static SQL and do
WHERE x is null or x > date_column?
However if you insist on using Dynamic SQL you should use a parameterized SQL statement using sp_executeSQL
Its easier to read, you don't have to use quotename, and you're protected from SQL Injection
DECLARE #Location int
DECLARE #FromDateCollected datetime
DECLARE #ToDateCollected datetime
SET #ToDateCollected = '1/02/2012'
DECLARE #sql nvarchar(max)
DECLARE #ParmDefinition nvarchar(max)
SET #ParmDefinition = N'#Location int , #FromDateCollected datetime, #ToDateCollected datetime ';
SET #sql = N'SELECT * from tblProgram WHERE 1=1'
IF (#Location IS NOT NULL)
BEGIN
SET #sql = #sql + N' AND Location = #Location'
END
IF (#FromDateCollected IS NOT NULL AND #ToDateCollected IS NOT NULL)
BEGIN
SET #sql = #sql + N' AND pw.DateCollected >= #FromDateCollected '
+ N' AND pw.DateCollected <= #ToDateCollected '
END
ELSE IF (#FromDateCollected IS NOT NULL AND #ToDateCollected IS NULL)
BEGIN
SET #sql = #sql + N' AND pw.DateCollected >= #FromDateCollected'
END
exec sp_executesql #SQL, #ParmDefinition, #Location = #Location,
#FromDateCollected = #FromDateCollected,
#ToDateCollected = #ToDateCollected
DEMO

GUID in dynamic sql

I am trying to use a column of type uniqueidentifier in Dynamic SQL.
I have a table X, with column ID of type guid.
If I do:
declare #primarykeyvalue varchar(50)
set #primarykeyvalue = '648D2DD7-0EB1-4E29-A996-69456753C460'
select * from X where ID = #primarykeyvalue
This works, but if I try to do the same in dynamic SQL like:
DECLARE #sql NVARCHAR(1000)
SET #sql = 'select * from X where ID = ' + #primarykeyvalue
EXECUTE(#sql)
This gives an syntax error as Incorrect syntax near 'D2DD7'.
Any suggestions please?
Change your code to:
DECLARE #sql NVARCHAR(1000)
SET #sql = 'select * from X where ID = ''' + #primarykeyvalue + ''''
EXECUTE(#sql)
Maybe you should think about using sp_executesql:
DECLARE #sql NVARCHAR(1000)
SET #sql = 'select * from X where ID = #key'
EXECUTE sp_executesql #sql, N'#key nvarchar(50)', #key = #primarykeyvalue
This enables you to use parameters in your queries and gets rid of the nasty doubled
single quotes.
You need extra quotes around your GUID value:
DECLARE #sql NVARCHAR(1000)
SET #sql = 'select * from X where ID = ''' + #primarykeyvalue + ''''
EXECUTE(#sql)

Conversion failed when converting the nvarchar value 'SELECT * FROM

Using Sql Server 2008, developed a view "vw_MasterView" I get this error:
Conversion failed when converting the nvarchar value 'SELECT * FROM VW_MASTERVIEW v WHERE 1=1 AND v.ClinicId = '' to data type int.
when I run the following stored procedure:
USE [xxxxxxx]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[ClientSummary1]
#LocationId int,
#startDate datetime,
#endDate datetime,
#userName nvarchar(50)
AS
declare #sql nvarchar(2000);
SET NOCOUNT ON
set #sql = 'SELECT * FROM VW_MASTERVIEW v WHERE 1=1 ';
IF #LocationId is not null
begin
set #sql = #sql + ' AND v.LocationId = ''' + #LocationId + '''';
end
if #userName is not null
begin
set #sql = #sql + ' AND (v.FirstUser = '' OR v.SecondUser = '')' + #userName + '''';
end
if #startDate is not null
begin
set #sql = #sql + ' AND v.FirstVisitDate = ''' + #startDate + '''';
end
if #endDate is not null
begin
set #sql = #sql + ' AND v.LastVisitDate = ''' + #endDate + '''';
end
EXEC(#sql)
I get both the LocationId and userName from a VS2010 application.
Thanks in Advance
When appending strings together in SQL Server, you have to cast non-textual types (such as int) to a textual type (such as varchar):
set #sql = #sql + ' AND v.LocationId = ''' +
cast(#LocationId as varchar(10)) + '''';
-- ^^^^ have to cast ^^ make sure size is big enough
Note that dynamic SQL should not be necessary in the first place. You can just run the query directly with the parameters (I implemented the null checks with the extra or conditions):
SELECT * FROM VW_MASTERVIEW v
WHERE (v.LocationId = #LocationId OR #LocationId is null)
AND (v.FirstUser = #userName OR v.Seconduser = #userName OR #userName is null)
AND (v.FirstVisitDate = #startDate OR #startDate is null)
AND (v.LastVisitDate = #endDate OR #endDate is null)
I may not have the logic right for FirstUser and SecondUser - I took an educated guess from your incomplete code.
Hope this helps!