Is it possible to pass an XML file as a parameter in a stored procedure in SQL Server?
I have tried this but it doesn't do what its supposed to:
DECLARE #XmlString2 as XML <--I have a feeling this is the problem
SET #XmlString2 = 'cast(x as XML)
from openrowset (bulk '''+#FileName+''', single_blob) as T(x)'
DECLARE cur CURSOR LOCAL for
SELECT
PA_ID = XTbl.value('(Answer_ID)[1]', 'varchar(400)'),
Question_ID = XTbl.value('(../../ID)[1]', 'bigint'),
QuestionText = XTbl.value('(../../QuestionText)[1]', 'varchar(200)'),
QuestionType = XTbl.value('(../../QuestionType)[1]','bigint'),
Questionaire_ID = XTbl.value('(../../QuestionaireID)[1]','bigint'),
Filter = XTbl.value('(../../Filter)[1]', 'bigint'),
Value = XTbl.value('(Value)[1]','varchar(400)'),
RequiresExplanation = XTbl.value('(RequiresExplanation)[1]','int'),
ReviewRequired = XTbl.value('(ReviewRequire)[1]','char(1)')
from #XmlString2.nodes('/Questions/Question/PossibleAnswers/PossibleAnswer') as XD(XTbl)
I have the same thing with a hardcoded address of the file and it works, so I was wondering if this is possible so as I can execute the stored procedure with a different file if I need to
Here's an example procedure that accepts XML as a string, and shreds it into tables. It's pretty gnarly to write this by hand, if you're doing many of these best to write some sort of generator based on your table definition.
The inputted xml is pretty simple, and attribute based
<xml>
<agent addr1='123 Main Street' city='Toronto' />
<agent addr1='123 Main Street' city='Toronto' />
</xml>
if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[sp_INSERT_agents]') and OBJECTPROPERTY(id, N'IsProcedure') = 1)
drop procedure [dbo].[sp_INSERT_agents]
GO
CREATE PROCEDURE sp_INSERT_agents
#strXML ntext
AS
BEGIN
-- NOTE: This procedure was generated by WCG:ITX DB/XML mapping utility
-- Please do not update this code by hand.
DECLARE #RC int
DECLARE #iDoc int
DECLARE #dtcurrenttime datetime
SET #dtcurrenttime = CURRENT_TIMESTAMP
-- Field variables
DECLARE #addr1 varchar(50)
DECLARE #addr2 varchar(50)
DECLARE #agentid char(13)
DECLARE #city varchar(50)
DECLARE #email varchar(50)
DECLARE #fax varchar(25)
DECLARE #mobile varchar(25)
DECLARE #muli char(1)
DECLARE #name varchar(50)
DECLARE #notes varchar(500)
DECLARE #phone varchar(25)
DECLARE #state char(2)
DECLARE #zip varchar(10)
DECLARE #part char(1)
EXECUTE sp_xml_preparedocument #iDoc OUTPUT, #strXML
-- Create a temporary return table
create table #return
( err varchar(50), agentid char(13))
-- Set NOCOUNT ON, to allow data to be returned from the temporary table.
SET NOCOUNT ON
DECLARE #ElementCursor CURSOR
SET #ElementCursor = CURSOR SCROLL DYNAMIC FOR
SELECT addr1, addr2, agentid, city, email, fax, mobile, muli, name, notes, phone, state, zip, part FROM OPENXML( #iDoc, "//agent", 2 )
WITH( addr1 varchar(50) '#addr1', addr2 varchar(50) '#addr2', agentid char(13) '#dt', city varchar(50) '#city', email varchar(50) '#email', fax varchar(25) '#fax', mobile varchar(25) '#mobile', muli char(1) '#muli', name varchar(50) '#name', notes varchar(500) '#notes', phone varchar(25) '#phone', state char(2) '#state', zip varchar(10) '#zip', part char(1) '#part')
OPEN #ElementCursor
FETCH NEXT FROM #ElementCursor INTO #addr1, #addr2, #agentid, #city, #email, #fax, #mobile, #muli, #name, #notes, #phone, #state, #zip, #part
BEGIN TRANSACTION
WHILE ##FETCH_STATUS = 0
BEGIN
-- Convert any temp values to real date time values
BEGIN
INSERT into dbo.agents
(addr1, addr2, agentid, city, email, fax, mobile, muli, name, notes, phone, state, zip, part, dtmodified)
values
(#addr1, #addr2, #agentid, #city, #email, #fax, #mobile, #muli, #name, #notes, #phone, #state, #zip, #part, #dtcurrenttime)
END
-- Check for any errors on the insert / update
IF ##error <> 0
BEGIN
INSERT into #return
(err)
values
(##error)
END
FETCH NEXT FROM #ElementCursor INTO #addr1, #addr2, #agentid, #city, #email, #fax, #mobile, #muli, #name, #notes, #phone, #state, #zip, #part
END
COMMIT TRANSACTION
CLOSE #ElementCursor
DEALLOCATE #ElementCursor
EXECUTE sp_xml_removedocument #iDoc
-- Return the temporary data, containing any errors
SELECT * from #return
END
GO
Related
I have a stored procedure that inserts records into the specified schema table using dynamic sql. To specify which schema you would like to insert into, it is done as follows:
EXEC Stored_Procedure_Name '[Schema_Name]', 'value1', 'value2', ...
The problem that I now face is that I wish to have a similar stored procedure that updates the table within a specified schema, as well as delete records within a specified schema's table, but I can't wrap my head around a method to accomplish this.
I've tried changing the code to make it UPDATE (instead of INSERT INTO) the tables but the logic behind it doesn't make any sense.
if object_id('AddUser_proc', 'AU') is not null
begin
drop proc AddUser_proc;
end;
GO
CREATE PROCEDURE AddUser_proc
(#branch VARCHAR(50),
#UserID NUMERIC(13,0),
#Username VARCHAR(50),
#Email VARCHAR(50),
#Fullname VARCHAR(100),
#Password BINARY(64),
#DateCreated DATETIME,
#ClosestBranch VARCHAR(50) )
AS
BEGIN
IF EXISTS(
SELECT 1
FROM Sys.Schemas
WHERE name = #branch
)
BEGIN
DECLARE #dynamic nvarchar(4000),
#paramDefinition nvarchar(4000)
SELECT #dynamic = N'INSERT INTO '+ quotename(#branch) + N'.User_tbl (
UserID,
Username,
Email,
Fullname,
Password,
DateCreated,
ClosestBranch
)
VALUES(#UserID, #Username, #Email, #Fullname, #Password, #DateCreated, #ClosestBranch)',
#paramDefinition =
N'#UserID numeric(13,0),
#Username varchar(50),
#Email varchar(50),
#Fullname varchar(100),
#Password binary(64),
#DateCreated datetime,
#ClosestBranch varchar(50)'
EXEC sp_executeSql #dynamic, #paramDefinition, #UserID, #Username, #Email, #Fullname, #Password,
#DateCreated, #ClosestBranch;
END
END
GO
Above is the code I have for the INSERT stored procedure. I would appreciate it if you could help me with a similar stored procedure that updates tables, as well as one that deletes records from tables. It would be ideal if all three (INSERT, UPDATE and DELETE) procedures could be contained within one stored procedure with the use of IF statements.
EDITED:
This is the SP that I have:
if object_id('UpdateUser_proc', 'UU') is not null
begin
drop proc UpdateUser_proc;
end;
GO
CREATE PROCEDURE UpdateUser_proc(
#branch varchar(50),
#UserID numeric(13,0),
#Username varchar(50),
#Email varchar(50),
#Fullname varchar(100),
#Password binary(64),
#DateCreated datetime,
#ClosestBranch varchar(50)
)
AS
BEGIN
IF EXISTS(
SELECT 1
FROM Sys.Schemas
WHERE name = #branch
)
BEGIN
DECLARE #dynamic nvarchar(4000),
#paramDefinition nvarchar(4000)
SELECT #dynamic = N'UPDATE '+ quotename(#branch) + N'.User_tbl
SET Username=#Username,Email=#Email,Fullname=#Fullname,Password=#Password,DateCreated=#DateCreated,ClosestBranch=#ClosestBranch
WHERE UserID=#UserID',
#paramDefinition =
N'#UserID numeric(13,0),
#Username varchar(50),
#Email varchar(50),
#Fullname varchar(100),
#Password binary(64),
#DateCreated datetime,
#ClosestBranch varchar(50)'
EXEC sp_executeSql #dynamic, #paramDefinition, #UserID, #Username, #Email, #Fullname, #Password,
#DateCreated, #ClosestBranch;
END
END
GO
And I execute it like so:
EXEC UpdateUser_proc 'Bloemfontein', '7928623003512', 'klover', 'test.g#g.com', 'John Snow', 'password', '20190303', 'Bloemfontein'
I have discovered that the problem may be due to the fact that the password field is a binary(64) type and I can't seem to use the HASHBYTES function within execution of the SP
As far as the DELETE SP goes, I have not attempted it yet as I have been stuck with the UPDATE SP.
I'm sure this is a easy fix, but I can't find an answer here. Been many a years since I have written stored procedures..
These are my procedures:
This first one works, and returns the newly created Id.
ALTER PROCEDURE [dbo].[sp_CreateBytegymType]
#Name NVARCHAR(200),
#Type NCHAR(1),
#Description NVARCHAR(MAX) NULL,
#Comment NVARCHAR(MAX) NULL,
#Source NVARCHAR(MAX) NULL,
#BtId INT OUTPUT
AS
BEGIN
SET NOCOUNT ON
INSERT INTO BytegymType
VALUES (#Name, #Type, #Description, #Comment, #Source)
SET #BtId = CAST(SCOPE_IDENTITY() AS INT)
END
The second one calls the first one:
ALTER PROCEDURE [dbo].[sp_CreateMuscle]
#Name NVARCHAR(200),
#Type NCHAR(1),
#Description NVARCHAR(MAX) NULL,
#Comment NVARCHAR(MAX) NULL,
#Source NVARCHAR(MAX) NULL,
#Group NVARCHAR(20) NULL
AS
BEGIN
DECLARE #BtId int
EXEC sp_CreateBytegymType
#Name = #Name,
#Type = #Type,
#Description = #Description,
#Comment = #Comment,
#Source = #Source,
#BtId = #BtId
INSERT INTO Muscle
VALUES (#BtId, #Group)
END
I get the following error:
Msg 515, Level 16, State 2, Procedure sp_CreateMuscle, Line 20 [Batch Start Line 2]
Cannot insert the value NULL into column 'BtId'
Seems I'm not keeping the #BtId value. Do I need to put it into a new value after executing the sp_CreateBytegymType?
Also I would like to do this in a transactional manner. So if the the insert into Muscle fails, it should rollback the stored procedure insert.
You need to add OUTPUT:
exec sp_CreateBytegymType
#Name = #Name,
#Type = #Type,
#Description = #Description,
#Comment = #Comment,
#Source = #Source,
#BtId = #BtId OUTPUT;
Also prefixing user defined stored procedures with sp_ is not advised. Related article: Is the sp_ prefix still a no-no?
I am inserting records using stored procedure and sp_executesql. Once I insert record using sp_executesql, i need the last inserted identity field value on that session.
ALTER proc [dbo].[spHoldTransaction]
#RegisterNo int,
#StoreID int,
#Department varchar(50),
#TransactionDateFrom date,
#TransactionDateTo date,
#Comment Varchar(50)
AS
BEGIN
DECLARE #RegisterID int;
DECLARE #DatabaseName varchar(15);
DECLARE #Batch int;
SELECT #RegisterID=ID FROM Register WHERE Register.Number = #RegisterNo;
SELECT #Batch = BatchNumber From Batch WHERE Status = 0 and RegisterID = #RegisterID
SET #DatabaseName = 'xxx'
SELECT #Department=''''+REPLACE(#Department,',',''',''')+''''
DECLARE #Qry nvarchar(MAX);
DECLARE #ParamDefinition nvarchar(MAX);
SET #ParamDefinition = N'#comment nvarchar(50),#StoreID int,#Batch int'
SET #Qry = '
INSERT INTO '+#DatabaseName+'.dbo.TransactionHold
(
[StoreID]
,[HoldComment]
,[BatchNumber]
,[ShippingNotes]
)
SELECT
#StoreID AS [StoreID]
,#Comment AS [HoldComment]
,#Batch AS [BatchNumber]
,'''' AS [ShippingNotes];
'
EXECUTE sp_executesql #Qry, #ParamDefinition, #Comment, #StoreID, #Batch
SELECT SCOPE_IDENTITY()
END
When I execute this above stored procedure, it's return empty. But TransactionHold has identity column Id
Try retrieving the identity inside the same scope of the execute sql procedure and return the value as an OUT parameter. Do these changes:
SET #ParamDefinition = N'#comment nvarchar(50),#StoreID int,#Batch int, #identity int out'
SET #Qry = '
INSERT INTO '+#DatabaseName+'.dbo.TransactionHold
(
[StoreID]
,[HoldComment]
,[BatchNumber]
,[ShippingNotes]
)
SELECT
#StoreID AS [StoreID]
,#Comment AS [HoldComment]
,#Batch AS [BatchNumber]
,'''' AS [ShippingNotes];
SET #identity = ##IDENTITY
'
DECLARE #identity INT
EXECUTE sp_executesql #Qry, #ParamDefinition, #Comment, #StoreID, #Batch, #identity OUT
SELECT #identity
I tried to define following SQL Server nested cursor statement: I loop calendars and migrate them from cut_calendar to sd_calendar. Each calendar also have calendar days. They are also moved by each calendar move.
DECLARE #id NUMERIC(20)
DECLARE #sdCalendarId NUMERIC(20)
DECLARE #calendarTypId NUMERIC(5)
DECLARE #name NVARCHAR(35)
DECLARE #description NVARCHAR(255)
DECLARE #ptyId NUMERIC(20)
DECLARE #lockCode NVARCHAR(20)
DECLARE #dataOwnerId NUMERIC(20)
DECLARE #cntId NUMERIC(20)
DECLARE #nonBusinessDaysMonday CHAR(1)
DECLARE #nonBusinessDaysTuesday CHAR(1)
DECLARE #nonBusinessDaysWednesday CHAR(1)
DECLARE #nonBusinessDaysThursday CHAR(1)
DECLARE #nonBusinessDaysFriday CHAR(1)
DECLARE #nonBusinessDaysSaturday CHAR(1)
DECLARE #nonBusinessDaysSunday CHAR(1)
DECLARE #ccyId NUMERIC(20)
DECLARE #code NVARCHAR(30)
DECLARE #version NUMERIC(10)
DECLARE #seal VARCHAR(255)
DECLARE #lstUpdTs DATETIME
DECLARE #day_id NUMERIC(20)
DECLARE #day_calDate DATETIME
DECLARE #day_lockCode NVARCHAR(20)
DECLARE #day_calComment NVARCHAR(255)
DECLARE #day_dataOwnerId NUMERIC(20)
DECLARE #day_calendarId NUMERIC(20)
DECLARE #day_calRecurring CHAR(1)
DECLARE #day_version NUMERIC(10)
DECLARE #day_seal VARCHAR(255)
DECLARE #day_lstUpdTs DATETIME
DECLARE #day_sdCalendarDaysId NUMERIC(20)
DECLARE #sdCodeId NUMERIC(20)
DECLARE cursorCutoffCalendar CURSOR FOR
SELECT ID, NAME, CALENDAR_TYP_ID,DESCRIPTION,PTY_ID,LOCK_CODE,DATA_OWNER_ID,CNT_ID,NON_BUSINESS_DAYS_MONDAY,NON_BUSINESS_DAYS_TUESDAY,NON_BUSINESS_DAYS_WEDNESDAY,NON_BUSINESS_DAYS_THURSDAY,NON_BUSINESS_DAYS_FRIDAY,NON_BUSINESS_DAYS_SATURDAY,NON_BUSINESS_DAYS_SUNDAY,CCY_ID,CODE,VERSION,SEAL,LST_UPD_TS
FROM CUT_CALENDAR
WHERE ID != 1
OPEN cursorCutoffCalendar
FETCH NEXT FROM cursorCutoffCalendar INTO #id, #name, #calendarTypId, #description, #ptyId, #lockCode, #dataOwnerId, #cntId, #nonBusinessDaysMonday, #nonBusinessDaysTuesday, #nonBusinessDaysWednesday, #nonBusinessDaysThursday, #nonBusinessDaysFriday, #nonBusinessDaysSaturday, #nonBusinessDaysSunday, #ccyId, #code, #version, #seal, #lstUpdTs
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT #sdCalendarId = COALESCE(MAX(ID),1) FROM SD_CALENDAR
SET #sdCalendarId = #sdCalendarId + 1
UPDATE CUT_CALENDAR_DAY
SET CALENDAR_ID = #sdCalendarId
WHERE CALENDAR_ID = #id
SELECT #sdCodeId = ID FROM SD_CALENDAR WHERE CODE = #code
IF #sdCodeId > 0
SET #code = CONCAT(#code, '_co')
ELSE
INSERT INTO SD_CALENDAR (ID, NAME, CALENDAR_ROLE_ID,DESCRIPTION,USE_IN_CUTOFF,PTY_ID,LOCK_CODE,DATA_OWNER_ID,CNT_ID,NON_BUSINESS_DAYS_MONDAY,NON_BUSINESS_DAYS_TUESDAY,NON_BUSINESS_DAYS_WEDNESDAY,NON_BUSINESS_DAYS_THURSDAY,NON_BUSINESS_DAYS_FRIDAY,NON_BUSINESS_DAYS_SATURDAY,NON_BUSINESS_DAYS_SUNDAY,CCY_ID,CODE,VERSION,SEAL,LST_UPD_TS)
VALUES(#sdCalendarId, #name, #calendarTypId,#description,1,#ptyId,#lockCode,#dataOwnerId,#cntId,#nonBusinessDaysMonday,#nonBusinessDaysTuesday,#nonBusinessDaysWednesday,#nonBusinessDaysThursday,#nonBusinessDaysFriday,#nonBusinessDaysSaturday,#nonBusinessDaysSunday,#ccyId,#code,#version,#seal,#lstUpdTs)
DECLARE cursorCutoffCalendarDays CURSOR FOR
SELECT ID, CAL_DATE, LOCK_CODE,CAL_COMMENT,DATA_OWNER_ID,CALENDAR_ID,CAL_RECURRING,VERSION,SEAL,LST_UPD_TS
FROM CUT_CALENDAR_DAY
WHERE ID != 1
OPEN cursorCutoffCalendarDays
FETCH NEXT FROM cursorCutoffCalendarDays INTO #day_id, #day_calDate, #day_lockCode, #day_calComment, #day_dataOwnerId, #day_calendarId, #day_calRecurring, #day_version, #day_seal, #day_lstUpdTs
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT #day_sdCalendarDaysId = COALESCE(MAX(ID),1) FROM SD_CALENDAR_DAY
SET #day_sdCalendarDaysId = #day_sdCalendarDaysId + 1
INSERT INTO SD_CALENDAR_DAY (ID, CAL_DATE, LOCK_CODE,CAL_COMMENT,DATA_OWNER_ID,CALENDAR_ID,CAL_RECURRING,VERSION,SEAL,LST_UPD_TS)
VALUES(#day_sdCalendarDaysId, #day_calDate, #day_lockCode, #day_calComment, #day_dataOwnerId, #day_calendarId, #day_calRecurring, #day_version, #day_seal, #day_lstUpdTs)
FETCH NEXT FROM cursorCutoffCalendarDays INTO #day_sdCalendarDaysId, #day_calDate, #day_lockCode, #day_calComment, #day_dataOwnerId, #day_calendarId, #day_calRecurring, #day_version, #day_seal, #day_lstUpdTs
END
CLOSE cursorCutoffCalendarDays
DEALLOCATE cursorCutoffCalendarDays
GO
DELETE FROM CUT_CALENDAR
WHERE ID = #id
FETCH NEXT FROM cursorCutoffCalendar INTO #sdCalendarId, #name, #calendarTypId, #description, #ptyId, #lockCode, #dataOwnerId, #cntId, #nonBusinessDaysMonday, #nonBusinessDaysTuesday, #nonBusinessDaysWednesday, #nonBusinessDaysThursday, #nonBusinessDaysFriday, #nonBusinessDaysSaturday, #nonBusinessDaysSunday, #ccyId, #code, #version, #seal, #lstUpdTs
END
CLOSE cursorCutoffCalendar
DEALLOCATE cursorCutoffCalendar
GO
Now when I run this, I get following error:
SQLServerException: Incorrect syntax near 'cursorCutoffCalendarDays'.
cursorCutoffCalendarDays is the inner cursor of my statement.
Try removing GO from:
CLOSE cursorCutoffCalendarDays
DEALLOCATE cursorCutoffCalendarDays
GO
And I agree with the comment you got from GarethD, I used to write cursors like this but then I asked how to do it without the cursor and got a nice explanation
Blockquote
Remove Go from this line then try
CLOSE cursorCutoffCalendarDays
DEALLOCATE cursorCutoffCalendarDays
I have written a stored procedure with the following format:
ALTER PROCEDURE usp_data_migration
(#sourceDatabase varchar(50),
#sourceTable varchar(50),
#targetDatabase varchar(50),
#targetTable varchar(50),
#finaloutput varchar(max) output)
AS
BEGIN
----Set of SQL Blocks
END
Then, I am executing the procedure:
DECLARE #finaloutput1 varchar(300)
EXEC usp_data_migration 'Yousuf', 'emp', '[City Branch]', 'emp_tgt', #finaloutput1 output
SELECT #finaloutput1
By executing this way I don't proper output.
When I execute this way:
DECLARE #finaloutput1 varchar(300)
EXEC usp_data_migration #sourceDatabase = 'Yousuf',
#sourceTable = 'emp',
#targetDatabase = '[City Branch]',
#targetTable = 'emp_tgt',
#finaloutput1 output
SELECT #finaloutput1
I get an error message saying:
Msg 119, Level 15, State 1, Line 41
Must pass parameter number 5 and subsequent parameters as '#name = value'. After the form '#name = value' has been used, all subsequent parameters must be passed in the form '#name = value'.
And if I removed my output parameter and execute the procedure, I get my desired output but I am not able to get my result as an output.
EXEC usp_data_migration #sourceDatabase = 'Yousuf',
#sourceTable = 'emp',
#targetDatabase = '[City Branch]',
#targetTable = 'emp_tgt'
What should I do?
Thanks in advance.
The error message is self-explanatory - you should name all of your parameters.
DECLARE #finaloutput1 varchar(300);
EXEC dbo.usp_data_migration -- always use schema prefix
#sourceDatabase = 'Yousuf',
#sourceTable = 'emp',
#targetDatabase = '[City Branch]',
#targetTable = 'emp_tgt',
#finaloutput = #finaloutput1 OUTPUT;
SELECT #finaloutput1;
You have to Select like this
Example 1
create procedure p1
(
#id INT,
#name varchar(20) OUTPUT,
#company varchar(20) OUTPUT
)
AS
BEGIN
Set #name = 'name'
Set #company = 'company'
select #name , #company from table1 where id = #id;
END
GO
Example 2
CREATE PROCEDURE Myproc
#parm varchar(10),
#parm1OUT varchar(30) OUTPUT,
#parm2OUT varchar(30) OUTPUT
AS
SELECT #parm1OUT='parm 1' + #parm
SELECT #parm2OUT='parm 2' + #parm
GO
DECLARE #SQLString NVARCHAR(500)
DECLARE #ParmDefinition NVARCHAR(500)
DECLARE #parmIN VARCHAR(10)
DECLARE #parmRET1 VARCHAR(30)
DECLARE #parmRET2 VARCHAR(30)
SET #parmIN=' returned'
SET #SQLString=N'EXEC Myproc #parm,
#parm1OUT OUTPUT, #parm2OUT OUTPUT'
SET #ParmDefinition=N'#parm varchar(10),
#parm1OUT varchar(30) OUTPUT,
#parm2OUT varchar(30) OUTPUT'
EXECUTE sp_executesql
#SQLString,
#ParmDefinition,
#parm=#parmIN,
#parm1OUT=#parmRET1 OUTPUT,#parm2OUT=#parmRET2 OUTPUT
SELECT #parmRET1 AS "parameter 1", #parmRET2 AS "parameter 2"
go
drop procedure Myproc
Please refer more here
Simple Example:
create procedure proc2 #var int out,#var2 varchar(10) out
as
begin
set #var=(select max(id) from customer);
set #var2=(select name from customer where id=#var);
end
declare #maxid int;
declare #maxname varchar(10);
exec proc2 #maxid out,#maxname out;
select #maxid,#maxname;