SET NOCOUNT ON;
DECLARE #sql NVARCHAR(MAX)
--,#DBName VARCHAR(30)
--SET #jobNumber=417133
--SELECT #DBName = DataBaseName,'tdis', #server = '[' + isnull(server,'s-portaldb1') + ']'
--from tdLogging.dbo.tblJobDbLookup where jobnumber = #jobNumber
DROP TABLE #Actual
CREATE TABLE #Actual (
jobnumber INT
,firstNameCounts VARCHAR(25)
,lastNameCounts VARCHAR(25)
,address1Counts VARCHAR(25)
,address2Counts VARCHAR(25)
,cityCounts VARCHAR(25)
,stateCounts VARCHAR(25)
,zipCounts VARCHAR(25)
,inHomeDateCounts VARCHAR(25)
)
SET #sql = 'INSERT INTO #actual (jobnumber,firstNameCounts,lastNameCounts , address1Counts, address2Counts, cityCounts, stateCounts, zipCounts, inHomeDateCounts) '
SET #sql = #sql + ' Select s.jobnumber, count(s.firstName) AS [firstNameCounts], Count (s.lastName) AS [lastNameCounts], Count (s.Address1) As [address1Counts], Count (s.address2)-Count (address2) AS '
SET #sql = #sql + ' [address2Counts], Count (s.City) AS [cityCounts], Count (s.State) AS [stateCounts], Count (s.Zip) AS [zipCounts], Count (jb.inHomeDate) AS [inHomeDateCounts] '
SET #sql = #sql + ' From [s-portaldb1].[tdis_417133].[dbo].[tblStandardFinal] s '
SET #sql = #sql + ' INNER JOIN [s-printstream].[tdSchedule2].[dbo].[tblJobTicketActions] jb '
SET #sql = #sql + ' ON jb.psFlagJobNumber = s.jobNumber '
SET #sql = #sql + ' where jobNumber = #jobNumber '
SET #sql = #sql + ' group by jobNumber '
PRINT #SQL
EXEC sp_executesql #sql
,N'#JobNumber Varchar(25)'
,#JobNumber = 417133;
SELECT *
FROM #Actual
I am trying to get this code to run dynamically and i wanted to have the "[s-portaldb1].[tdis_417133]" come on the run means dynamically.
any help would be greatly appreciated. Thank you
Not sure I know what "come on the run" means, but if you are trying to make the server name dynamic in your dynamic SQL, just add a parameter for your server name and then introduce that to your SQL using something like the following:
DECLARE #ServerName varchar(100) = '[s-portaldb1].[tdis_417133]'
SET #sql = #sql + ' From ' + #Servername + '.[dbo].[tblStandardFinal] s '
Related
This my current code and is working fine.I need the proper syntax to make the fieldname a variable.
For example:
SET #firstname = ''' + #value + ''''
declare #SQL NVARCHAR(4000),#listid nvarchar(50), #value nvarchar(50), #fieldname nvarchar(50)
-- interfering with SELECT statements.
SET NOCOUNT ON;
set #listid = '80000003-1525450413'
set #value = 'dennis4'
set #fieldname = 'firstname'
set #SQL ='Update openquery(QRemote, ''select * from customer WHERE listID = ''''' + #listid + ''''''')
SET firstname = ''' + #value + ''''
EXEC sp_executesql #SQL;
Firstname is a column within Quick Books. All I want is to make it a dynamic parameter. As you can see listID and value are parameters. I would Like to do the following: SET #SQL2 = 'Set #fieldname = ''' + #value + '''' Then I can execute it with EXEC sp_executesql #sql + #sql2.
i am using sql server 2008 r2, I have created a dynamic stored procedure because this is my requirement to implement to filteration of data based on certain conditions. I am not able to get value into #RecordCount
ALTER PROCEDURE [dbo].[sp_getAssetListAudit]
#type nvarchar(20),
#typeid nvarchar(5),
#clientId nvarchar(5),
#PageIndex nvarchar(5),
#PageSize nvarchar(5),
#RecordCount nvarchar(5) output
AS
BEGIN
SET NOCOUNT ON;
DECLARE #SQL nvarchar(max)
SET #SQL ='
select ROW_NUMBER() OVER ( ORDER BY ad.arid ASC )
AS rownum, ad.arid,ad.ast_code,ad.ast_descp,isnull(cat.name,'''') ''cat'',ISNULL(loc.name,'''') ''loc'',isnull(gp.name,'''') ''grp'',
isnull(cc.name,'''') ''cc'' ,
ad.ast_qty ''qty'' into #Results
from tbl_AssetDetails ad
left join tbl_Category cat on ad.ast_cat = cat.catid
left join tbl_Subcategory scat on ad.ast_subcat = scat.subcatid
left join tbl_Location loc on loc.lid = ad.ast_loc
left join tbl_Group gp on gp.gid = ad.ast_grp
left join tbl_CostCenter cc on cc.ccid = ad.ast_costcen
where ad.ast_status not in (3,-1) AND ad.clientId = '+#clientId+' AND '
IF(#type='cat')
SET #SQL = #SQL +' ad.ast_cat='+#typeid+' AND '
IF(#type='subcat')
SET #SQL = #SQL +' ad.ast_subcat='+#typeid+' AND '
IF(#type='loc')
SET #SQL = #SQL +' ad.ast_loc='+#typeid+' AND '
IF(#type='grp')
SET #SQL = #SQL +' ad.ast_grp='+#typeid+' AND '
IF(#type='cc')
SET #SQL = #SQL +' ad.ast_costcen='+#typeid+' AND '
IF(#type='ast')
SET #SQL = #SQL +' ad.arid='+#typeid+' AND '
SET #SQL = #SQL +' 1=1 '
SET #SQL =#SQL + ' SELECT '+#RecordCount+' = count(*) FROM #Results '
SET #SQL = #SQL +' SELECT * FROM #Results WHERE rownum
BETWEEN('+#PageIndex+' -1) * '+#PageSize+' + 1 AND((('+#PageIndex+' -1) * '+#PageSize+'+ 1) + '+#PageSize+') - 1 '
SET #SQL = #SQL + ' drop table #Results '
EXEC sp_executesql #SQL, #RecordCount OUTPUT
END
I am not able to get value into #RecordCount and subsequently no result set.
You need to assign the value to the OUTPUT parameter:
SET #SQL =#SQL + ' SELECT #RecordCount = count(*) FROM #Results; '
You also need to pass the parameter definitions to sp_executesql as in #wannuanguo's answer. You should use also use parameters for #typeid, #pageindex, etc. too instead of literals in the query.
Add the second parameter for sp_executesql:
EXEC sp_executesql #SQL, N'#RecordCount nvarchar(5) output',#RecordCount OUTPUT
I have the following modification of my stored procedure:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[spTMSA_Test_Run]
#TableName nvarchar(200) = 'MyTable',
#Parent int = 1145,
#Name nvarchar(100) = '''Test''',
#KPI nvarchar(max) = '''Test''',
#IDCount int = 1137
AS
BEGIN
EXEC('UPDATE ' + #TableName + ' SET Parent = ' + #Parent + ', Name = ' + #Name + ' , KPI = ' + #KPI + ' WHERE IDCount = ' + #IDCount)
END
This procedure is executed successfully if I gave ''' before and after the string value. In case I left ' before and after the string value it will cause error.
Please help me find the reason why and solution as well. Thanks
This procedure is an open door for SQL injection attacks.
Unless you have a really good reason why you need it to create dynamic SQL, I would suggest avoiding it.
If you can't avoid using dynamic sql, the least you can do is to use quotename to keep your procedure a little safer.
As to the problem you state in your question - just move the ''' to the query body:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[spTMSA_Test_Run]
#TableName nvarchar(200) = 'MyTable',
#Parent int = 1145,
#Name nvarchar(100) = 'Test',
#KPI nvarchar(max) = 'Test',
#IDCount int = 1137
AS
BEGIN
EXEC('UPDATE QUOTENAME(' + #TableName + ')
SET Parent = ' + #Parent + ',
Name = ''' + #Name + ''' ,
KPI = ''' + #KPI + '''
WHERE IDCount = ' + #IDCount)
END
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[spTMSA_Test_Run]
#TableName nvarchar(200) = 'MyTable',
#Parent int = 1145,
#Name nvarchar(100) = '''Test''',
#KPI nvarchar(max) = '''Test''',
#IDCount int = 1137
AS
BEGIN
declare #sql nvarchar(4000)
set #sql='UPDATE ' + #TableName + ' SET Parent = ' + #Parent + ', Name = ' + #Name + ' , KPI = ' + #KPI + ' WHERE IDCount = ' + #IDCount
print #sql --find reason in the sql statement
EXEC(#sql)
END
I suggest to use sp_executesql and CAST int to nvarchar before executing query and QUOTENAME the #tablename.
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[spTMSA_Test_Run]
#TableName nvarchar(200),
#Parent int,
#Name nvarchar(100),
#KPI nvarchar(max),
#IDCount int
AS
BEGIN
DECLARE #sql nvarchar(max)
SELECT #sql = '
UPDATE ' + QUOTENAME(#TableName) + '
SET Parent = ' + CAST(#Parent as nvarchar(10))+ ',
Name = ''' + #Name + ''',
KPI = ''' + #KPI + '''
WHERE IDCount = ' + CAST(#IDCount as nvarchar(10)) + ';'
EXEC sp_executesql #sql
END
I am trying this in SQL Server and it throws an error:
ALTER PROCEDURE [dbo].[GET_TEXT_DETAIL]
#id UNIQUEIDENTIFIER,
#table VARCHAR(255),
#field VARCHAR(MAX)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #sql VARCHAR(200)
SET #sql = 'select ' + QUOTENAME(#field) + ' from ' + QUOTENAME(#table) + ' where ID = ' + QUOTENAME(#id)
EXEC (#sql)
END
I get this error:
Msg 207, Level 16, State 1, Line 1
Invalid column name 'CFC2776A-6EE1-E511-A172-005056A218B0'.
Is there any way to do this so I don't have to make a bunch or procedures to pull text from a bunch of different tables?
QUOTENAME has optional second parameter quote char, so you were close and this could be solved by:
... QUOTENAME(#id, '''')
but the most proper way for this case is passing the parameter:
set #cmd = '
SELECT t.' + QUOTENAME(#field) + '
FROM ' + QUOTENAME(#table) + ' t
WHERE t.ID = #ID'
exec sp_executesql #cmd, N'#ID uniqueidentifier', #ID
And server will be able to reuse plan as #srutzsky mentioned. Because #ID is no longer part of a query text and #cmd text remains the same for different #ID (and same #table+#field).
ALTER PROCEDURE [dbo].[GET_TEXT_DETAIL]
(
#id UNIQUEIDENTIFIER,
#table SYSNAME,
#field SYSNAME
)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #SQL NVARCHAR(MAX)
SET #SQL = '
SELECT ' + QUOTENAME(#field) + '
FROM ' + QUOTENAME(#table) + '
WHERE ID = ''' + CAST(#id AS VARCHAR(36)) + ''''
--PRINT #SQL
EXEC sys.sp_executesql #SQL
END
What is the best way to achieve this
INSERT INTO #TableName (#ColumnNames)
EXEC sp_executesql #SQLResult;
Where #TableName, #ColumnNames, #SQLResult are varchar variables
I am trying to avoid do a separate insert for each table.
The best way is to write (or generate) all reqiured procedures for all table. 23 tables times 4 procedures (insert, update, delete and select) that can be generated automatically is nothing in dev time and pain compared to the so called "generic solution".
It's a path to poor perfomance, unreadable code, sql injection hazard and countless debuging hours.
First of all I appreciate all your comments. And I agree that SQL dynamic is a pain to debug (Thanks God, management studio has this possibility). And, of course there are hundreds of different solutions
I solved it in this way finally, more or less I try to explain why this solution of SQL dynamic. The client uses xlsx spreadsheets to enter certain data, so I read the spreadsheets and I insert the (data depends on the spreadsheet to insert into the proper table). Later the data in the tables are exported to XML to send a third party sofware.
SET #SEL = N'';
DECLARE sel_cursor CURSOR
FOR (SELECT sc.name as field
FROM sys.objects so INNER JOIN sys.columns sc ON so.[object_id]=sc.[object_id]
WHERE so.name= #TableName and sc.name not in ('InitDate', 'EndDate', 'Version', 'Status'));
SET #SEL = ''; set #i = 0;
OPEN sel_cursor
FETCH NEXT FROM sel_cursor INTO #field
WHILE ##FETCH_STATUS = 0
BEGIN
set #sel = #sel + ', '+ #field
set #i = 1;
FETCH NEXT FROM sel_cursor INTO #field
END
CLOSE sel_cursor;
DEALLOCATE sel_cursor;
SET #SQL = N''
SET #SQL = #SQL + N'SELECT * INTO XLImport FROM OPENROWSET'
SET #SQL = #SQL + N'('
SET #SQL = #SQL + N'''Microsoft.ACE.OLEDB.12.0'''+','
SET #SQL = #SQL + N'''Excel 12.0 Xml; HDR=YES;'
SET #SQL = #SQL + N'Database='+#file +''''+ ','
SET #SQL = #SQL + N'''select * from ['+ #SheetName + '$]'''+');'
EXEC sp_executesql #SQL
SET #SQL = N'';
SET #SQL = #SQL + N'
SELECT '+''''+CAST(#initDate AS VARCHAR(10))+'''' +', '+ ''''+CAST(#endDate AS VARCHAR(10))+''''
+ ', '+ CAST(#version AS VARCHAR(2)) +', ' +''''+#status+''''
+ #SEL
+' FROM DBO.XLImport '
DECLARE cols_cursor CURSOR
FOR (Select COLUMN_NAME From INFORMATION_SCHEMA.COLUMNS where table_name = #tableName);
SET #SEL = ''; set #i = 0;
OPEN cols_cursor
FETCH NEXT FROM cols_cursor INTO #field
WHILE ##FETCH_STATUS = 0
BEGIN
set #sel = #sel + #field + ', '
set #i = 1;
FETCH NEXT FROM cols_cursor INTO #field
END
CLOSE cols_cursor;
DEALLOCATE cols_cursor;
SET #SEL = LEFT(#SEL, LEN(#SEL) - 1) -- remove last ,
SET #SQL = N''
SET #SQL = #SQL + N'SELECT * INTO XLImport FROM OPENROWSET'
SET #SQL = #SQL + N'('
SET #SQL = #SQL + N'''Microsoft.ACE.OLEDB.12.0'''+','
SET #SQL = #SQL + N'''Excel 12.0 Xml; HDR=YES;'
SET #SQL = #SQL + N'Database='+#file +''''+ ','
SET #SQL = #SQL + N'''select * from ['+ #SheetName + '$]'''+');'
EXEC sp_executesql #SQL
SET #SQLString =
N'INSERT INTO '+ #TableName + '('+ #SEL +') ' + #SQL;
EXEC sp_executesql #SQLString
Use EXECUTE sp_executesql #sql, here is example:
create proc sp_DynamicExcuteStore
#TableName varchar(50),
#ColumnNames varchar(50),
#SQLResult varchar(max)
as
declare #sql nvarchar(max) = '
INSERT INTO '+#TableName+' ('+#ColumnNames+')
EXEC sp_executesql '+#SQLResult
EXECUTE sp_executesql #sql
go
create proc sp_test
as
select 'test' + convert(varchar,RAND())
go
CREATE TABLE [dbo].[Test](
[text1] [nvarchar](500) NULL
) ON [PRIMARY]
GO
DECLARE #return_value int
EXEC #return_value = [dbo].[sp_DynamicExcuteStore]
#TableName = N'Test',
#ColumnNames = N'text1',
#SQLResult = N'proc_test'
SELECT 'Return Value' = #return_value
GO
SELECT TOP 1000 [text1]
FROM [test].[dbo].[Test]