Something better for this situation than using IF? - sql-server-2008

I am writing queries that are used on a website. When the query is needed it gets directly parsed to the server and the outcome is all controlled by the query. The website just returns the table. What I do have on the site is checkboxes that the client can select and those get parsed into the query as either #var = 1 or #var = 0. Because of that, right now I have this code to check and add or not depending if it is checked. My question is, is there a better way to go about this than using the IF statement like this as I have several sections of the code that include this:
SET #sql = 'select distinct '
If #mgchk = 1
SET #sql = #sql + 'p.MainGroup'
If #sgchk = 1 and #sql = 'select distinct '
SET #sql = #sql + 'p.SubGroup'
If #sgchk = 1 and #sql not like '%SubGroup'
SET #sql = #sql + ',p.SubGroup'
If #ssgchk = 1 and #sql = 'select distinct '
SET #sql = #sql + 'p.SubSubGroup'
If #ssgchk = 1 and #sql not like '%SubSubGroup'
SET #sql = #sql + ',p.SubSubGroup'
If #Seasonchk = 1 and #sql = 'select distinct '
SET #sql = #sql + 'p.Season'
If #Seasonchk = 1 and #sql not like '%Season'
SET #sql = #sql + ',p.Season'
If #vendorchk = 1 and #sql = 'select distinct '
SET #sql = #sql + 'p.VendorID'
If #vendorchk = 1 and #sql not like '%VendorID'
SET #sql = #sql + ',p.VendorID'
SET #sql =
#sql +
' into
##aa
from
RPProducts p,
RPIv i,
RPTrsd d,
RPTrs s
WHERE
s.StoreID = d.StoreID and
s.ReceiptNO = d.ReceiptNO and
i.UPC = d.UPC and
i.StoreID = d.StoreID and
i.IVProduct = p.Productid and
s.TRSdate >= '''+ convert(varchar(10), #trsfrom, 101) +''' and
s.TRSdate <= '''+ convert(varchar(10), #trsto, 101) +''''
execute sp_executesql #sql
#mgchk / #sgchk / #ssgchk / #seasonchk / #vendorchk are the checkboxes variables
To answer #Aaron,
Global temp because of the dynamic queries. The whole query gets processed and drop right away when the data is pulled. No clash will happen there.
My date variables are datetime and it gives me an error within dynamic SQL.
Yes, recalling the same thing over to check, which is the reason for this whole question, if there is something better to use than the IF checking.
And I find using alias joins easier...

-- rather than convert to a dangerously formatted string,
-- here is a much better way to strip time from a datetime
-- (if you need to!)
SET #trsfrom = DATEADD(DAY, DATEDIFF(DAY, 0, #trsfrom), 0);
SET #trsto = DATEADD(DAY, DATEDIFF(DAY, 0, #trsto), 0);
DECLARE #sql NVARCHAR(MAX) = N'SELECT DISTINCT ';
-- here's an easier way to strip the first comma:
SET #sql += SUBSTRING(
CASE WHEN #mgchk = 1 THEN ',p.MainGroup' ELSE '' END
+ CASE WHEN #sgchk = 1 THEN ',p.SubGroup' ELSE '' END
+ CASE WHEN #ssgchk = 1 THEN ',p.SubSubGroup' ELSE '' END
+ CASE WHEN #Seasonchk = 1 THEN ',p.Season' ELSE '' END
+ CASE WHEN #vendorchk = 1 THEN ',p.VendorID' ELSE '' END, 2, 2000);
SET #sql += ' INTO ##aa
FROM
dbo.RPProducts AS p -- use schema prefix!
INNER JOIN dbo.RPIv AS i -- use PROPER JOINS!
ON i.IVProduct = p.Productid
INNER JOIN dbo.RPTrsd AS d
ON i.UPC = d.UPC
AND i.StoreID = d.StoreID
INNER JOIN dbo.RPTrs AS s
ON s.StoreID = d.StoreID
AND s.ReceiptNO = d.ReceiptNO
WHERE s.TRSdate >= #trsfrom -- use strongly typed parameters!
AND s.TRSdate <= #trsto;';
EXEC sp_executesql #sql,
N'#trsfrom DATETIME, #trsto DATETIME',
#trsfrom, #trsto;
----^^^^^^^^^^^^^^^^ here is how the query gets the #trsfrom & #trsto values
I still think your use of a ##global temp table is quite dangerous. If two people run this code at the same time, they are going to have serious problems.

Related

SQL Server - Unable to run cursor FETCH statement dynamically stored in variable

I've a cursor which fetch dynamic number of columns because the "SELECT STATEMENT" which I use to declare this cursor is dynamic.
Since I do not know at any point of time, how many columns this cursor will have, I cannot declare fixed number of variables into fetch.
So I have built FETCH statement as dynamic and stored in one #variable... but when i run fetch statement using EXEC sp_executesql
its failing with error ..Must declare the scalar variable "#objcursor".
I know that #objcursor variable is not accessible becasue while sp_executesql run which run on isolate THREAD
is there any way someone can advise, how to handle this code to run without an error?
Here is my T-SQL code:
/* ==== Variable Declaration ==== */
declare #AllValues nvarchar(max)
declare #objcursor as cursor
declare #MonthCount integer
declare
#vsql as nvarchar(max)
,#vquery as nvarchar(max)
,#id as int
,#value as varchar(50)
BEGIN
SELECT #AllValues = CASE
WHEN t.column_id=1 THEN
(COALESCE(#AllValues +'"', '')+ t.name)+'"'
WHEN t.column_id > 1 THEN
(COALESCE(#AllValues + ',"', '') + t.name)+'"'
END
FROM
(
SELECT sc.name, sc.column_id FROM sys.objects o
INNER JOIN sys.columns sc ON o.object_id = sc.object_id
WHERE o.name = 'temp_daywise' AND o.type = 'U' AND (sc.name like '%Curr Yr%' or column_id=1)
) AS t
ORDER BY t.column_id
SET #AllValues='SELECT "'+#AllValues+' FROM dbo.temp_daywise'
set #vquery = #AllValues
set #vsql = 'set #cursor = cursor forward_only static for ' + #vquery + ' open #cursor;'
exec sys.sp_executesql
#vsql
,N'#cursor cursor output'
,#objcursor output
---Handling Dynamic number of columns in a cursor, get the column count first and build FETCH statement dynamically
Select #CurCount=COUNT(*) from sys.columns where object_id in(
SELECT object_id from sys.objects where name = 'dbo.temp_daywise' and type = 'U' )
and (name like '%Curr Yr%');
SET #LoopCount = 1
--here building my fetch statement
SET #fetchsql ='fetch next from #objcursor into #AgreementID'
WHILE #LoopCount <= #CurCount
BEGIN
SET #fetchsql = #fetchsql+','+'#CY_Day'+CONVERT(VARCHAR(2),#LoopCount)
SET #LoopCount = #LoopCount + 1
END
--EXEC #fetchsql
EXEC sp_executesql #fetchsql
while (##fetch_status = 0)
begin
BEGIN
'update ...here something'
END
EXEC #fetchsql
end
close #objcursor
deallocate #objcursor
END
Here is my data and expected resullts:
1) My dynamic cusror will read column name from sys.columns because coulmns are not static that's based on columns count I'm building FETCH statement. following code build cusrsor SELECT statement
SELECT #AllValues = CASE
WHEN t.column_id=1 THEN
(COALESCE(#AllValues +'"', '')+ t.name)+'"'
WHEN t.column_id > 1 THEN
(COALESCE(#AllValues + ',"', '') + t.name)+'"'
END
FROM
(
SELECT sc.name, sc.column_id FROM sys.objects o
INNER JOIN sys.columns sc ON o.object_id = sc.object_id
WHERE o.name = 'temp_daywise' AND o.type = 'U' AND (sc.name like '%Curr Yr%' or column_id=1)
) AS t
ORDER BY t.column_id
SET #AllValues='SELECT "'+#AllValues+' FROM dbo.temp_daywise'
set #vquery = #AllValues
set #vsql = 'set #cursor = cursor forward_only static for ' + #vquery + ' open #cursor;'
exec sys.sp_executesql
#vsql
,N'#cursor cursor output'
,#objcursor output
2) I want to update fetch data into following table for columns Day1...Day31. if cusrsor found 20 columns data will update until CY_Day20.
3) In short, i do not know the cusror retrieving columns at design time so i can't produce fetching variable. Since columns are known at run tiume, i have to build fetch & update statment in while loop as like below:
Note: ignore DECLARE which is on start of the code... but i placed here to get an idea.
DECLARE
#CY_Day1 Numeric(18,2), #CY_Day2 Numeric(18,2), #CY_Day3 Numeric(18,2), #CY_Day4 Numeric(18,2), #CY_Day5 Numeric(18,2),
, #CY_Day7 Numeric(18,2), #CY_Day8 Numeric(18,2), #CY_Day9 Numeric(18,2), #CY_Day10 Numeric(18,2), #PY_Day10 Numeric(18,2), #CY_Day11 Numeric(18,2), #CY_Day12 Numeric(18,2),........ #CY_Day31 Numeric(18,2)
Select #CurCount=COUNT(*) from sys.columns where object_id in(
SELECT object_id from sys.objects where name = 'dbo.temp_daywise' and type = 'U' )
and (name like '%Curr Yr%');
SET #LoopCount = 1
SET #fetchsql ='fetch next from #objcursor into #AgreementID'
SET #updatesql ='UPDATE dbo.TPDD_Report_Monthly_Details SET '
WHILE #LoopCount <= 2
BEGIN
SET #fetchsql = #fetchsql+','+'#CY_Day'+CONVERT(VARCHAR(2),#LoopCount)
SET #updatesql= #updatesql +'CY_Day'+CONVERT(VARCHAR(2),#LoopCount)+' = #CY_Day'+CONVERT(VARCHAR(2),#LoopCount)+',CY_TPDD_Day'+CONVERT(VARCHAR(2),#LoopCount)+' = (#CY_Day'+CONVERT(VARCHAR(2),#LoopCount)+'/1/1),'
SET #LoopCount = #LoopCount + 1
END
SET #updatesql =#updatesql + ' dss_update_time = #v_dss_update_time WHERE AgreementId = #AgreementID and TpddYear=CONVERT(VARCHAR(4),#Current_year)+CONVERT(VARCHAR(4),#Previous_year) and Running_Month = #MonthNo'
--EXEC #fetchsql
PRINT #fetchsql
PRINT #updatesql
---executing FETCH statement
EXEC sp_executesql #fetchsql
while (##fetch_status = 0)
begin
BEGIN
---updating table columns
EXEC sp_executesql #updatesql
END
EXEC #fetchsql
end
close #objcursor
deallocate #objcursor
Finally my cusrsor fetch & udpate statement will looks like below:
fetch next from #objcursor into #AgreementID,#CY_Day1,#CY_Day2,#CY_Day3,#CY_Day4,#CY_Day5,#CY_Day6,#CY_Day7,#CY_Day8,#CY_Day9,#CY_Day10
UPDATE dbo.TPDD_Report_Monthly_Details SET
CY_Day1 = #CY_Day1, CY_TPDD_Day1 = (#CY_Day1/1/1),
CY_Day2 = #CY_Day2, CY_TPDD_Day2 = (#CY_Day2/1/1),
CY_Day3 = #CY_Day3, CY_TPDD_Day3 = (#CY_Day3/1/1),
CY_Day4 = #CY_Day4, CY_TPDD_Day4 = (#CY_Day4/1/1),
CY_Day5 = #CY_Day5, CY_TPDD_Day5 = (#CY_Day5/1/1),
CY_Day6 = #CY_Day6, CY_TPDD_Day6 = (#CY_Day6/1/1),
CY_Day7 = #CY_Day7, CY_TPDD_Day7 = (#CY_Day7/1/1),
CY_Day8 = #CY_Day8, CY_TPDD_Day8 = (#CY_Day8/1/1),
CY_Day9 = #CY_Day9, CY_TPDD_Day9 = (#CY_Day9/1/1),
CY_Day10 = #CY_Day10, CY_TPDD_Day10 = (#CY_Day10/1/1),
dss_update_time = #v_dss_update_time
WHERE AgreementId = #AgreementID
Hope I;m able to present my problem correctly.
I have a good start. You're probably going to have to tweak a few things. I did my best to get it as close as possible as your actual situation. Hope this helps. If you have any questions, let me know.
NOTE I USE THE SAME TABLE NAMES AND DROP THEM.
IF OBJECT_ID('dbo.temp_daywise') IS NOT NULL
DROP TABLE dbo.temp_daywise;
IF OBJECT_ID('dbo.TPDD_report_Monthly_Details') IS NOT NULL
DROP TABLE dbo.TPDD_report_Monthly_Details;
CREATE TABLE dbo.temp_daywise
(
AgreementID CHAR(6),
RunningMonth INT,
[Curr Yr1] VARCHAR(100),
[Curr Yr2] VARCHAR(100),
[Curr Yr3] VARCHAR(100)
);
INSERT INTO temp_daywise
VALUES ('A10001',3,'col1_1','col2_1','col3_1'),
('A10003',3,'col1_2','col2_2','col3_2'),
('A10006',3,'col1_3','col2_3','col3_3'),
('A10008',3,'col1_4','col2_4','col3_4');
CREATE TABLE dbo.TPDD_report_Monthly_Details
(
TpddYear DATE,
AgreementID CHAR(6),
RunningMonth INT,
[CY_Day1] VARCHAR(100),
[CY_Day2] VARCHAR(100),
[CY_Day3] VARCHAR(100)
);
INSERT INTO TPDD_report_Monthly_Details
VALUES ('20131220','A10001',3,NULL,NULL,NULL),
('20131220','A10003',3,NULL,NULL,NULL),
('20131220','A10006',3,NULL,NULL,NULL),
('20131220','A10008',3,NULL,NULL,NULL);
--Now that I've created my versions of your table, here's the actual code
--Variable to hold columns that need to be updated
DECLARE #ColToBeUpdated VARCHAR(MAX);
--Gets your column information for temp_daywise
WITH CTE_temp_daywise_Cols
AS
(
SELECT *
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'temp_daywise'
)
--Now join temp_daywise columns to TPDD_report columns
--QUOTENAME() add's brackets [] around each column
SELECT #ColToBeUpdated = COALESCE(#ColToBeUpdated + ',','') + QUOTENAME(A.COLUMN_NAME) + ' = B.' + QUOTENAME(B.COLUMN_NAME)
FROM INFORMATION_SCHEMA.COLUMNS A
INNER JOIN CTE_temp_daywise_Cols B
--The "+1" compensates for difference in ordinal positions
ON A.Ordinal_Position = B.ORDINAL_POSITION + 1
--This makes the table alisaed A to only get columns for TPDD_report
WHERE A.TABLE_NAME = 'TPDD_report_Monthly_Details'
--Don't return AgreementID
AND A.COLUMN_NAME != 'AgreementID'
AND B.COLUMN_NAME != 'AgreementID'
ORDER BY A.ORDINAL_POSITION
--Variable to hold code
DECLARE #sql VARCHAR(MAX);
SELECT #sql = 'UPDATE dbo.TPDD_Report_Monthly_Details
SET ' + #ColToBeUpdated +'
FROM dbo.TPDD_Report_Monthly_Details AS A
INNER JOIN temp_daywise AS B
ON A.AgreementID = B.AgreementID'
--Look at code
--Notice you can join on AgreementID and just set the columns equal to each other
SELECT #sql;
--To execute
--EXEC(#sql)
Results stored in #sql:
UPDATE dbo.TPDD_Report_Monthly_Details
SET [RunningMonth] = B.[RunningMonth],
[CY_Day1] = B.[Curr Yr1],
[CY_Day2] = B.[Curr Yr2],
[CY_Day3] = B.[Curr Yr3]
FROM dbo.TPDD_Report_Monthly_Details AS A
INNER JOIN temp_daywise AS B
ON A.AgreementID = B.AgreementID

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

Dynamic SQL concatenation

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'

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!