Dynamic SQL shows successful but does not update rows - sql-server

I am new to SQL Server and stored procedures, with that being said I am using SQL Server 2008 R2 trying to make a dynamic query that allows me to pass in the table name and a few parameters to update some rows.
The stored procedure runs and says completed successfully but the rows never get updated. If I break up the queries and run them individually they work but all together nothing.
I tried using print and select statements to show my queries and progress but nothing prints out.
ALTER PROCEDURE [dbo].[sp_testing_drew]
-- Add the parameters for the stored procedure here
#Table_Name sysname,
#id int,
#username varchar(25)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
DECLARE #recipeName varchar(25),
#idApp varchar(10),
#DynamicSQL1 nvarchar(4000),
#DynamicSQL2 nvarchar(4000),
#DynamicSQL3 nvarchar(4000),
#DynamicSQL4 nvarchar(4000)
-- Set the recipe name, finding it first by its ID
--SELECT #recipeName = Recipe_Name FROM LC2Recipes WHERE LC2RecipesID = 551;
SET #DynamicSQL1 = N'SELECT '+#recipeName+' = Recipe_Name FROM '+#Table_Name+' WHERE LC2RecipesID = '+CAST(#id AS varchar(10))+';'
EXECUTE sp_executesql #DynamicSQL1
-- Get the ID of the approved recipe
--SET #DynamicSQL2 = N'SELECT TOP 1 ' + #idApp + ' = ' + #Table_Name + 'ID FROM ' + #Table_Name + ' WHERE Recipe_Name = ''' + #recipeName + ''' ORDER BY Major_Revision DESC;'
SET #DynamicSQL2 = N'SELECT TOP 1 '+#idApp+' = LC2RecipesID FROM '+#Table_Name+' WHERE Recipe_Name = '''+#recipeName+''' ORDER BY Major_Revision DESC;'
EXECUTE sp_executesql #DynamicSQL2
-- 4 is Archived, 1 is approved, set the user who approved
--SET #DynamicSQL3 = N'UPDATE ' + #Table_Name + ' SET Status = 4 WHERE Recipe_Name = ''' + #recipeName + '';
SET #DynamicSQL3 = N'UPDATE '+#Table_Name+' SET Status = 4 WHERE Recipe_Name = '''+#recipeName+''';'
EXECUTE sp_executesql #DynamicSQL3
--SET #DynamicSQL4 = N'UPDATE ' + #Table_Name + ' SET Approved_By = ''' + #username + ''', Status = 1 WHERE ' + #Table_Name + 'ID = ' + CAST(#idApp AS varchar(10));
SET #DynamicSQL4 = N'UPDATE '+#Table_Name+' SET Approved_By = '''+#username+''', Status = 1 WHERE '+#Table_Name+'ID = '+#idApp+';'
EXECUTE sp_executesql #DynamicSQL4
END

You need to set the values of variable #recipeName & #idApp. This is causing the problem , just set the values of these variable and you should be fine,

Related

SQL Server Linked Server Openquery

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.

Challenge with dynamic SQL

I have a procedure that generates dynamic SQL that creates an insert into statement while querying an excel spreadsheet.
The resulting print from the messages screen can be pasted into an ssms window and executes. When I try to execute the SQL from within the stored procedure I get a syntax error as follows:
'SELECT * into TestClient FROM OPENROWSET('Microsoft.ACE.OLEDB.12.0', 'Excel 12.0;HDR=YES;Database=G:\CustomerETL\Employee\PendingETL\ETLEmployeexls.xls;', [Sheet1$])'
Msg 102, Level 15, State 1, Line 15
Incorrect syntax near 'SELECT * into TestClient FROM OPENROWSET('.
Below is the entire stored procedure. I know the problem is in the ticks (within the SET blocks that create the dynamic SQL I just can't figure out where the missing ticks are.
Here is the proc:
USE [ETL]
GO
/****** Object: StoredProcedure [dbo].[ImportExcelSheetForCustomerEmployeeUpdate2] Script Date: 12/19/2017 4:03:05 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[ImportExcelSheetForCustomerEmployeeUpdate2](#BatchID int)
as
--EXEC ImportExcelSheetForCustomerEmployeeUpdate 2
/* -- TRUNCATE TABLE FilesToImport
UPDATE FilesToImport
SET StatusID = 1
*/
-- Jeffery Williams
-- 12/18/2017
DECLARE #FileID int
,#ETLFilename varchar(250)
,#ClientName varchar(100)
,#FileType varchar(5)
,#ColumnCount int
,#RowsToETL int
,#StatusID int
,#Processed bit = 0
,#Count int
,#SQL nvarchar(4000)
,#Sheetname varchar(50) = '[Sheet1$]'
,#CMDSQL as varchar(4000)
,#SQLCmd NVARCHAR(MAX)
SELECT *
FROM FilesToImport
BEGIN
SELECT #Count = count(*)
FROM FilesToImport
WHERE BatchID = #BatchID
AND StatusID = 1
END
PRINT 'Count of records to process: ' + cast(#Count as varchar)
WHILE #Count > 0
BEGIN
BEGIN
SELECT TOP 1 #FileID = FileID, #ETLFilename = ETLFilename, #ClientName = ClientName
,#FileType = FileType, #ColumnCount = ColumnCount, #RowsToETL = RowsToETL
FROM FilesToImport
WHERE StatusID = 1
AND BatchID = #BatchID
END
-- Rename the file
set #CMDSQL = 'rename G:\CustomerETL\Employee\PendingETL\' + #ETLFilename + ' ETLEmployeexls.xls'
exec master..xp_cmdshell #CMDSQL
--PRINT cast(#cmdsql as varchar(4000))
-- Ciode below generates our select. Need to add an INTO clause and create a staging table for each import. Prior to this step we need to rename the file.
SET #SQL = ''''
SET #SQL = #SQL + 'SELECT * into ' + coalesce(#ClientName, 'TestClient') + ' FROM OPENROWSET('
SET #SQL = #SQL + ''''
SET #SQL = #SQL + '''' + 'Microsoft.ACE.OLEDB.12.0' + '''' --+ ', '
-- Excel 12.0;HDR=NO;Database=g:\UnZip\ImportSampleXLSX.xlsx;' + ''
SET #SQL = #SQL + '''' + ', '
SET #SQL = #SQL + '''' + '''Excel 12.0;HDR=YES;Database=G:\CustomerETL\Employee\PendingETL\ETLEmployeexls.xls;''' + '''' + ', ' + #Sheetname + ')'
SET #SQL = #SQL + ''''
PRINT cast(#SQL as varchar(8000))
EXEC sp_executesql #SQL
set #CMDSQL = 'rename G:\CustomerETL\Employee\PendingETL\ETLEmployeexls.xls ' + #ETLFilename
exec master..xp_cmdshell #CMDSQL
UPDATE FilesToImport
SET StatusID = 2
WHERE FileID = #FileID
/* -- TRUNCATE TABLE FilesToImport
UPDATE FilesToImport
SET StatusID = 1
*/
SET #Count = (#Count - 1)
CONTINUE
END
I am posting this as an answer but it should be comment. When I tried adding this as a comment StackOveflow kept thinking that I was trying to add #count as an email target.
In your code:
WHILE #Count > 0
BEGIN
BEGIN
SELECT TOP 1 #FileID = FileID, #ETLFilename = ETLFilename, #ClientName = ClientName
,#FileType = FileType, #ColumnCount = ColumnCount, #RowsToETL = RowsToETL
FROM FilesToImport
WHERE StatusID = 1
AND BatchID = #BatchID
END
you are not updating the value of #count. This will either never loop or loop forever. You probably want to add a statement (right before the end) such as this:
Set #count= ##rowcount;
Ben

Dynamic SQL update Image

I have been battling with this statement:
ALTER PROCEDURE [dbo].[transact_image_update]
-- Add the parameters for the stored procedure here
#transact_recordID_int int,
#image1_bin image,
#image2_bin image,
#transact_referenceNo_str nvarchar(25),
#userID_last uniqueidentifier,
#tableName nvarchar(50)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
DECLARE #sqlUpdt01 nvarchar(4000)
SET #sqlUpdt01 = '
Update [dbo].[' + #tableName + '] SET [image1_bin] = '+ CONVERT(VARCHAR(MAX), CONVERT(VARBINARY(MAX), #image1_bin), 2)
+ ', [image2_bin] = '+ CONVERT(VARCHAR(MAX), CONVERT(VARBINARY(MAX), #image2_bin), 2)
+', [userID_last] = '''+ convert(nvarchar(4000),#userID_last)
+ ''' WHERE (transact_recordID_int = '+convert(varchar,#transact_recordID_int) +')
AND ([transact_referenceNo_str] = ''' +convert(varchar, #transact_referenceNo_str)
+''' )
AND (locked_bol = 0)
'
exec sp_executesql #sqlUpdt01
Basically, I have many DB tables with similar schema but different names (for types of transactions) and would like this ONE procedure to make the update given the table name as argument. This script compiles successfully but execution cannot update the image field. Is there a conversion I'm missing?
Please help.
in correct type cast in below line
in correct line
+ ''' WHERE (transact_recordID_int = '+ convert(varchar,#transact_recordID_int) +
correct line
+ ''' WHERE (transact_recordID_int = '+ #transact_recordID_int +

How to create a UDF or View in another database that references the correct sys.objects table in the caller?

Using SQL Server 2008, I'd like to create a UDF that gives me the create date of an object. This is the code:
create function dbo.GetObjCreateDate(#objName sysname) returns datetime as
begin
declare #result datetime
select #result = create_date from sys.objects where name = #objname
return #result
end
go
I'd like to put this UDF in the master database or some other shared database so that it is accessible from anywhere, except that if I do that then the sys.objects reference pulls from the master database instead of the database that I'm initiating my query from. I know you can do this as the information_schema views sit in master and just wrap calls to local instances of sys.objects, so I'm hoping there's a simple way to do that with my UDF as well.
Try this:
CREATE FUNCTION dbo.GetObjCreateDate(#objName sysname, #dbName sysname)
RETURNS datetime AS
BEGIN
DECLARE #createDate datetime;
DECLARE #params nvarchar(50);
DECLARE #sql nvarchar(500);
SET #params = '#createDate datetime OUTPUT';
SELECT #sql = 'SELECT #createDate = create_date FROM ' + #dbName + '.sys.objects WHERE name = ''' + #objname + '''';
EXEC sp_executesql #sql, #params, #createDate = #createDate OUTPUT;
RETURN #createDate
END
;
Why not do this instead?
Create a stored procedure that creates a view in the master database containing all of the information in sys.objects from each database on the server.
Create a DDL Trigger that gets fired whenever a CREATE, ALTER or DROP statement is executed for a database. The trigger would then execute the stored procedure in step #1. This allows the view to be automatically updated.
(Optional) Create a user defined function that queries the view for the creation date of a given object.
Stored Procedure DDL:
USE [master];
GO
CREATE PROCEDURE dbo.BuildAllServerObjectsView
AS
SET NOCOUNT ON;
IF OBJECT_ID('master.dbo.AllServerObjects') IS NOT NULL
EXEC master..sp_SQLExec 'DROP VIEW dbo.AllServerObjects;';
IF OBJECT_ID('tempdb..Databases') IS NOT NULL
DROP TABLE #Databases;
DECLARE #CreateView varchar(8000);
SET #CreateView = 'CREATE VIEW dbo.AllServerObjects AS' + CHAR(13)+CHAR(10) + CHAR(13)+CHAR(10);
SELECT name COLLATE SQL_Latin1_General_CP1_CI_AS AS 'name'
INTO #Databases
FROM sys.databases
ORDER BY name;
DECLARE #DatabaseName nvarchar(100);
WHILE (SELECT COUNT(*) FROM #Databases) > 0
BEGIN
SET #DatabaseName = (SELECT TOP 1 name FROM #Databases ORDER BY name);
SET #CreateView +='SELECT N'+QUOTENAME(#DatabaseName, '''')+' AS ''database_name''' + CHAR(13)+CHAR(10)
+ ' ,name COLLATE SQL_Latin1_General_CP1_CI_AS AS ''object_name''' + CHAR(13)+CHAR(10)
+ ' ,object_id' + CHAR(13)+CHAR(10)
+ ' ,principal_id' + CHAR(13)+CHAR(10)
+ ' ,schema_id' + CHAR(13)+CHAR(10)
+ ' ,parent_object_id' + CHAR(13)+CHAR(10)
+ ' ,type' + CHAR(13)+CHAR(10)
+ ' ,type_desc' + CHAR(13)+CHAR(10)
+ ' ,create_date' + CHAR(13)+CHAR(10)
+ ' ,modify_date' + CHAR(13)+CHAR(10)
+ ' ,is_ms_shipped' + CHAR(13)+CHAR(10)
+ ' ,is_published' + CHAR(13)+CHAR(10)
+ ' ,is_schema_published' + CHAR(13)+CHAR(10)
+ ' FROM ' + QUOTENAME(#DatabaseName) + '.sys.objects';
IF (SELECT COUNT(*) FROM #Databases) > 1
SET #CreateView += CHAR(13)+CHAR(10) + CHAR(13)+CHAR(10) + ' UNION' + CHAR(13)+CHAR(10);
ELSE
SET #CreateView += ';';
DELETE #Databases
WHERE name = #DatabaseName;
END;
--PRINT #CreateView --<== Uncomment this to see the DDL for the view.
EXEC master..sp_SQLExec #CreateView;
IF OBJECT_ID('tempdb..Databases') IS NOT NULL
DROP TABLE #Databases;
GO
Function DDL:
USE [master];
GO
CREATE FUNCTION dbo.GetObjCreateDate(#DatabaseName sysname, #objName sysname) RETURNS DATETIME AS
BEGIN
DECLARE #result datetime;
SELECT #result = create_date
FROM master.dbo.AllServerObjects
WHERE [database_name] = #DatabaseName
AND [object_name] = #objname;
RETURN #result;
END
GO
Sample Usage:
SELECT master.dbo.GetObjCreateDate('MyDatabase', 'SomeObject') AS 'Created';
SELECT master.dbo.GetObjCreateDate(DB_NAME(), 'spt_monitor') AS 'Created';
Does it have to be a function? If you just want it accessible everywhere, a trick is to put your code in a varchar and sp_executesql it:
create procedure dbo.GetObjCreateDate(#objName sysname)
as
declare #sql nvarchar(max)
select #sql = 'select create_date from sys.objects where name = ''' + #objname + ''''
EXEC sp_executesql #sql
go
There seems to be an undocumented stored procedure that allows you to create your own system objects: sp_ms_marksystemobject
You can read more on http://www.mssqltips.com/tip.asp?tip=1612
Have a look at How to Write Your Own System Functions. I believe that it may help you

DDL statements with variables for table and column names

In my stored procedure, I make a temp_tbl and want to add several columns in a cursor or while loop. All works fine the cursor (the creation of a temp_bl but I can´t add the column when the column string is in a varchar variable.
WHILE ##FETCH_STATUS = 0
BEGIN
SET #webadressenrow = 'Webadresse_'+CAST(#counter as nchar(10))
ALTER TABLE IVS.tmpBus
ADD #webadressenrow varchar(500) Null
fetch next from cur_web into #webadressen
SET #counter = #counter + 1
END
The code above results in a syntax error, while this code works:
WHILE ##FETCH_STATUS = 0
BEGIN
SET #webadressenrow = 'Webadresse_'+CAST(#counter as nchar(10))
ALTER TABLE IVS.tmpBus
ADD SOMECOLUMNAME varchar(500) Null
fetch next from cur_web into #webadressen
SET #counter = #counter + 1
END
Can anybody give me a syntax hint to this small problem?
You won't be able to parameterise the ALTER TABLE statement but you could build up the SQL and execute it something like this:
declare #sql nvarchar(max)
set #sql = 'create table IVS.tmpBus ( '
select
#sql = #sql + 'Webadresse_' +
row_number() over ( order by col ) +
' varchar(500) null, '
from sourceData
set #sql = substring(#sql, 1, len(#sql) - 2) + ' )'
exec #sql
Be careful about security/SQL-Injection attacks though.
Generally speaking DDL statements i.e. those that define tables and columns do not accept variables for table or column names.
You can sometimes get around that by preparing the statements but support for prepared DDL is not provided by all database engines.
The following example works in SQL Server 2005, although I would suggest that adding columns dynamically may not be the optimal solution
DECLARE #colname1 VARCHAR(10)
DECLARE #colname2 VARCHAR(10)
DECLARE #sql VARCHAR(MAX)
SET #colname1 = 'col1'
SET #colname2 = 'col2'
SET #sql = 'CREATE TABLE temptab (' + #colname1 + ' VARCHAR(10) )'
EXEC (#sql)
INSERT INTO temptab VALUES ('COl 1')
SET #sql = 'ALTER TABLE temptab ADD ' + #colname2 + ' VARCHAR(10)'
EXEC (#sql)
INSERT INTO temptab VALUES ('Col1', 'Col2')
SELECT * FROM temptab
DROP TABLE temptab
Produced the following results
col1 col2
---------- ----------
COl 1 NULL
Col1 Col2
i have Solved The Problem with the Non optimal Way.
The Code Works prefectly for me. i Hope another frustrated programmer can Use this.
DECLARE cur_web CURSOR FOR
SELECT IVS.LG_Webadressen.Adresse FROM IVS.LG_Webadressen WHERE IVS.LG_Webadressen.FK_GID = #welche
open cur_web /*Cursor wird geöffnet*/
fetch next from cur_web into #webadressen /*Erster Datensatz wird geholt*/
WHILE ##FETCH_STATUS = 0 /*Solange eine Datensatz vorhanden ist*/
BEGIN
/*Spalte Adden*/
SET #webadressenrow = 'Webadresse_'+CAST(#counter as nchar(1)) /*Anhängen des Durchlaufes an den Spaltennamen*/
SET #sql = 'ALTER TABLE IVS.temp_tbl ADD ' + #webadressenrow + ' VARCHAR(100)' /*Spalte adden*/
EXEC (#sql)
/*Wert für die Webadresse wird reingeschrieben*/
SET #sql = 'UPDATE IVS.temp_tbl Set ' + #webadressenrow + ' = ''' + #webadressen + ''' WHERE GID = ' + CAST(#welche as nchar(10)) + ''
EXEC(#sql)
/*nächtser Datensatz wird geholt*/
fetch next from cur_web into #webadressen
SET #counter = #counter + 1
END
/*Cursor zerstören und Schließen*/
CLOSE cur_web
DEALLOCATE cur_web

Resources