XML DML Replace with a Function Result - sql

I would like to dynamically replace the value of an XML Element, in selected XML value(s) being retrieved from a table. This replacement needs to be performed by a function that I would like to call. I can't even begin to find any clues to point me in the right direction...
I have the follow code snippet (incomplete) that I believe is the correct structure for using XPath to get to the element I want, and to qualify by XPath which records I am interested in (one or more), from there I have no idea how to take the result of the called function, and ideally place the result in a sql:column:
UPDATE [database].[dbo].[table_with_xml]
SET table_with_xml.modify('replace value of (//PrimaryApplicant/FName/text())[1] with sql:column("")')
FROM [database].[dbo].[table_with_xml] AS [XML_Table]
WHERE [XML_Table].XML_Field.value('(//HeaderData/CountryCode/text())[1]', 'varchar(100)') = '123'

First of all, if you want to update table data from a function, you aren't allowed to do it. You can use a stored proc though. You can send 'replace value of' statement (from you syntax above) to it dynamically and send the value with which you want to replace. Here's some code to demonstrate what I'm trying to say:
Create PROC changeXML
#xmlPath nvarchar(max), -- the statement 'replace value of'
#value nvarchar(max) -- the new value
AS
BEGIN
DECLARE #pathString nvarchar(max), #sql NVARCHAR(MAX);
-- create full statement dynamically
SET #pathString = 'replace value of ('+#xmlPath+'text())[1] with ("'+#value+'")';
SELECT #pathString;
-- create dynamic sql and pass pathstring to it.
SET #sql = 'UPDATE [dbo].[tableWithXmlData] SET a.modify(''#p'')';
-- execute dynamic sql
EXEC sp_executesql #sql, N'#p nvarchar(max)', #p = #pathString
END
Then run proc something like this:
EXEC [dbo].[chnageXML] #xmlPath = N'path to your xml value',
#value = N'new value'

Related

query inside the variable

Is it possible in SQL to use a variable to store query.
For example to save time when subquery is used multiple times inside the main query.
Example:
DECLARE #my_query as varchar(250) = select x from my_table where my_table = y.your_table
SELECT
a,b,c,(#my_query),d,e,f
FROM my_table_1
Is it possible in SQL to use a variable to store query.
Depend on your definition of "query". If you mean store the text which we use to execute the command, then the answer is YES. If you mean an object type query, then the answer is not - since there is no data type that fit this.
What I mean is that a variable can store a value which is string. The string can be any query command that you want. Therefore, you can store for example the text "select col1,col2 from table1".
Next you need to ask how can we use this text in order to execute it as part of a query, which is done using dynamic query.
We can execute a text of a query using the build-in stored procedure sp_executesql, which is build for such needs.
For example:
-- DECLARE VARIABLE
DECLARE #MyQuery NVARCHAR(MAX)
-- SET the value of the variable
SET #MyQuery = 'SELECT ''Yes I can'''
-- Executing a dynamic query
EXECUTE sp_executesql #MyQuery
Here is another example which look more close to your question:
-- First let's create a table
CREATE TABLE T(ID INT)
INSERT T(ID) VALUES (1),(2)
GO
-- And here is what you sked about:
-- DECLARE VARIABLE
DECLARE #MyQuery NVARCHAR(MAX)
-- SET the value of the variable
SET #MyQuery = 'select ID from T where ID = ''1'''
-- Let's combine the text to a full query now
DECLARE #FullQuery NVARCHAR(MAX)
SET #FullQuery = '
SELECT
ID,(' + #MyQuery + ')
FROM T
'
PRINT #FullQuery
-- Executing a dynamic query
EXECUTE sp_executesql #FullQuery
NOTE! Your specific sample of query will return error, which is not related to the question "Is it possible in SQL to use a variable to store query". This is a result of the "query" is not well formatted.
Important! It is HIGHLY recommended to read the document about this stored procedure and learn a bit more of the options it provides us.
https://learn.microsoft.com/en-us/sql/relational-databases/system-stored-procedures/sp-executesql-transact-sql?view=sql-server-ver15

SQL Server stored procedure passing parameters into variables

I have a big query which works and I want to write a stored procedure for it.
I'm getting this error:
the OLE DB provider SQLNCLI11" for linked server "theServer" does not contain the table ""#dbName"."dbo"."tableName"
What I am trying to do:
create PROCEDURE [sys.sp_myProcedure]
(
#dbName varchar(30) output,
#rid varchar (10) output,
#mdate output
)
AS
BEGIN
declare #prt varchar(12)
declare #pid int
declare #cid int
--declare #rid int
declare #aid int
SET NOCOUNT ON;
set #cid= (select CID from theServer.[#dbName].dbo.tableName where RID= #rid)
set #pid= (select PID from theServer.[#dbName].dbo.tableName where RID= #rid)
set #aid= (select aid from theServer.[#dbName].dbo.tableName where RID= #rid)
--then my query begins
theServer.[#dbName].dbo.tablename is a linked server.
What I want to do is:
execute [sys.sp_myProcedure] 'someDbname', '123', '2012-03-03'
and the parameters passed here would set/update the variables #dbName, #rid, #mdate at runtime. ( #mdate I have it further away in the query, it's too big to adapt it with myTable and to change all the sensitive data).
How can I do this ?? (using SQL Server 2012)
edit (based on the comments and answers):
so, it's #thatString = '--insert the query here ' . Then, in my case how can i set those variables according to the parameters inside the query? Should i do it with replace? like this: set #thatString= replace(#thatString, dbName, #dbname) ?
**
edit 2
**
set #sql = '
use [someDbName];
use [123];
use [2012-03-03];
select ... '
set #sql = replace (#sql, 'someDbName', #dbName)
set #sql = replace (#sql, '123', #rid)
set #sql = replace (#sql, '2012-03-03', #mdate)
execute #sql
end
Did i get it right? is the execute #sql in the right place?
I'm asking cause it doesnt work. i'm getting the name ' --part of my query here' is not a valid identifier
Names of databases or other objects cannot be specified dynamically from variables. The workaround is to compose a dynamic SQL query in a string, into which you concatenate the required names, and then execute (#thatString).
(You might think you can employ use, but it is scoped such that you would have to include the rest of your query within the same executed string.)
--
Edit with more info as requested. You can compose the string however you like. If you need any more guidance, there are plenty of pages that discuss dynamic T-SQL. But hey, two ideas:
set #myDynamicQuery =
'
use [' + #myDynamicDatabase + '];
select BLAH from WHOM where DATA = ''what'';
';
or if you will be using the name a lot, you could reduce the hassle caused by breaking in and out of single quotes as follows - though I personally never use this as I don't like how it looks:
set #myDynamicQuery =
'
use [A_RARE_PLACEHOLDER];
select BLAH from WHOM where DATA = ''what'';
-- lots more uses of A_RARE_PLACEHOLDER
';
set #myDynamicQuery = replace(
#myDynamicQuery,
'A_RARE_PLACEHOLDER',
#myDynamicDatabase
);
Then execute (#myDynamicQuery);

sql server - fill results from executed query string in a temp table dynamically

I'm writing a stored procedure. I have a string which contains an sql query. For example:
DECLARE #sql nvarchar(max)
SET #sql = (N'SELECT pkOrderID FROM Orders')
(Just to note: this isn't what the select statement looks like. This is just an example of what I mean) I then want to execute the string and put the result in a temporary table E.g. #tempTable. I know EXEC(#sql) exists but not sure if it will do me any good in this situation. The other twist is that I do not know the names of all the columns in the returned #sql so the temp table #tempTable needs to be created dyanmically based off the return from #sql. Thanks for any help.
I think you could use SELECT INTO to do what you want but it would mean updating your string:
DECLARE #sql nvarchar(max)
SET #sql = (N'SELECT frompkOrderID INTO #tmporders FROM Orders')
then you should be able to run EXEC #sql to create the table
more information about SELECT INTO here : http://msdn.microsoft.com/en-au/library/ms188029.aspx
There is no simple way to do this. The problem with #JanR's solution is that the #tmporders table will be out of scope to the script that calls your stored procedure (ie It will produce an error like "Invalid object name '#rtmporders'"
One alternative is to use a global temp table (eg ##tmporders).
So your SP might look like this:
CREATE PROCEDURE TestSP
AS
BEGIN
SELECT pkOrderID INTO ##tmporders FROM Orders
END
GO
And the calling script might be like:
EXEC TestSP
SELECT * FROM ##temporders

Store result of dynamic SQL generating XML to XML Variable

So I have found plenty of examples across SO that show how to assign the result of dynamic SQL to variables but I have yet to find one that does it the way that I am trying to... So either I am going about this the wrong way or I just haven't found the proper syntax to perform this correctly.
Basically, I am trying to create an XML record of a row from a table before deleting the row from the table (think of it as an audit of the table) using a Stored Procedure. I was attempting to do this through dynamic SQL so that the Stored Procedure can be called from multiple other Stored Procedures that perform Delete operations on their corresponding tables, but before doing so they pass the necessary information (the #sql variable which will contain the select statement to obtain the record) to this Audit Stored Procedure.
Create Procedure dbo.AuditDelete(
#sql NVARCHAR(200),
#TableName VARCHAR(50),
#UserName NVARCHAR(256)
)
AS
DECLARE #XML XML
BEGIN
--at this point #sql will contain a select statement written by the calling stored procedure
--which is specifically written to return the record that is being deleted, example:
#sql = select * from my.table where tableId = 1 FOR XML AUTO
execute sp_executesql #sql, N'#XML XML OUTPUT', #XML = XML OUTPUT;
SELECT #XML
--I was doing this as a check to ensure that XML has the record
--because the execute command returned the XML record, but #XML is null...
--and I can't figure out why
--code for inserting into the Audit table
So I'm sure that its either some syntax I'm missing or perhaps I'm just going about this the wrong way. Any suggestions?
Note: this is being done in SSMS on SQL Server 2008 R2
You need to assign the result your query to the parameter in the dynamic SQL.
set #sql = N'set #XML = (select * from my.table where tableId = 1 FOR XML AUTO)'
execute sp_executesql #sql, N'#XML XML OUTPUT', #XML OUTPUT

Retrieve parameter value from parameter name as a string in SQL

I am trying to use some dynamic sql. I have generated over 100 parameters, and to speed things up I am trying to use dynamic sql to only insert values into a table that I have to based off of information retrieved from other tables. I have tried many things like adding a cast etc.
Example of what I mean:
DECLARE #var1 NVARCHAR(MAX)
-- Loop through and add various values
SET #var1 = #var1 + #parameterName
-- The parameter name is retrieved from a table that holds this information
the problem is that when I add the parameter name which would be like "#myFirstParameter" into my final expression so something like this:
DECLARE #finalString NVARCHAR(MAX)
SET #finalString = 'INSERT INTO myTableName ([myFirstParameter]) VALUES (#myFirstParameter)'
EXEC(#finalString)
The "#myFirstParameter" does not get replaced by it's value and I get the following error:
Must declare the scalar variable "#myFirstParameter".
Does anyone know of a way to go from the string name of a parameter to the actual value? I am trying to avoid hardcoding all the values and any work around I have attempted has failed and given me errors which appear to be much worse than what I have stated above.
The first way is to add the parameter's value, instead of its name, to the SQL string:
SET #finalString = 'INSERT INTO myTableName ([myFirstParameter]) VALUES (' +
#myFirstParameter + ')'
This assumes the parameter has a string value. If not, you have to cast it, like cast(#myFirstParameter as varchar(128)).
The second way is to use sp_executesql instead of exec:
exec sp_executesql
N'INSERT INTO myTableName ([myFirstParameter]) VALUES (#myFirstParameter)',
N'#myFirstParameter varchar(128)',
#myFirstParameter = #myFirstParameter;