Dynamic SQL issue - sql-server-2008

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.

Related

Use Union with while

Go
Alter procedure SOW_proc
as
begin
declare #i int
set #i = 1
declare #j int
set #j = 1
While(#i <= 84)
Begin
select ' ' as 'SOW_Id', ' ' as 'SOW_description', ' ' as 'CostCenter',
' ' as 'CostCenter_description', ' ' as 'CostCenter_type', Profit,
Revenue, Expenses, ' ' as 'Currency'
from Fact_table where SOW_Id is null
union all
Select 'Total' + '-' + SOW_table.SOW_Id, SOW_table.SOW_description, ' ', ' ', ' ',
SOW_VW.Profit, SOW_VW.Revenue, SOW_VW.Expenses, SOW_VW.Currency
from SOW_TABLE, SOW_VW
where SOW_table.SOW_Id = SOW_VW.SOW_ID and SOW_TABLE.SOW_RowID = #i
while(#j = #i)
Begin
select ' ' as 'SOW_Id', ' ' as 'SOW_description', ' ' as 'CostCenter',
' ' as 'CostCenter_description', ' ' as 'CostCenter_type', Profit, Revenue,
Expenses, ' ' as 'Currency'
from Fact_table where SOW_Id is null
union all
Select SOW_TABLE.SOW_ID, SOW_TABLE.SOW_description, CostCenter_table.CostCenter,
CostCenter_table.CostCenter_desc, CostCenter_table.Project_type,
CostCenter_vw.Profit, CostCenter_vw.Revenue, CostCenter_vw.Expenses,
CostCenter_VW.Currency
from SOW_TABLE, CostCenter_table, CostCenter_vw, Fact_table
where SOW_TABLE.SOW_ID = FACT_TABLE.SOW_Id
and FACT_TABLE.CostCenter_id = CostCenter_table.CostCenter_Id
and CostCenter_table.CostCenter_id = CostCenter_vw.CostCenter_id
and SOW_TABLE.SOW_RowID = #j
set #j = #j + 1;
end
Set #i = #i + 1
end
end
When I run the above code, I got this result. I am unable to upload the pic due to insufficient points.
What I want is to remove all the headings between two rows as same heading is used.
I am not able to use 'union all' as 'union all' can't be used with 'while'.
Please suggest some way to do that.

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)

Something better for this situation than using IF?

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.

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'

Make dynamic this kind of query

I am making a query to create a table which has twice elements in SQL
SELECT [att1]
,[att2]
,[att3]
,[att4]
,[att5]
,[att6]
,[att7]
,[att8]
,[att9]
,[att10]
,att11 = att1,
att12 = att2,
att13 = att3,
att14 = att4,
att15 = att5,
att16 = att6,
att17 = att7,
att18 = att8,
att19 = att9,
att20 = att10
INTO Table_20
FROM Table_10;
What would be the best way to make this dynamic and if I have a table with 30 atts, make a table with 30 * 2 atts (double the size)?
DECLARE
#table NVARCHAR(512) = N'dbo.Table_10';
#sql NVARCHAR(MAX) = N'',
#c INT;
SELECT #sql += N',' + name
FROM sys.columns
WHERE [object_id] = OBJECT_ID(#table)
AND name LIKE 'att%';
SELECT #c = ##ROWCOUNT;
SELECT #sql += N',att' + CONVERT(VARCHAR(12),
#c + CONVERT(INT, REPLACE(name, 'att', '')))
+ ' = ' + name
FROM sys.columns
WHERE [object_id] = OBJECT_ID(#table)
AND name LIKE 'att%';
SELECT #sql = N'SELECT ' + STUFF(#sql, 1, 1, '')
+ ' INTO dbo.Table_20 FROM ' + #table + ';';
PRINT #sql;
-- EXEC sp_executesql #sql;