The xmlns attribute in the following code stops me getting the value I need. Works fine with any other attribute but not xmlns. I have no control over the xml I'm given - how can I get the CrpId value?
declare #CrpId int, #i int, #xml xml
set #xml =
'<NewProgressReportResult xmlns="http://myDomain.com/crp">
<CrpId>2160</CrpId>
</NewProgressReportResult>'
exec sp_xml_preparedocument #i output, #xml
select
CrpId
from openxml (#i, 'NewProgressReportResult', 2)
with (
CrpId int 'CrpId'
)
exec sp_xml_removedocument #i
I don't know OpenXML at all myself, but this FAQ seems to have the answer. Basically it's because you've got elements in a particular namespace (due to the xlmns attribute) so you need to be able to specify the same namespace in your query.
Converting this to your particular problem, I think you want:
declare #CrpId int, #i int, #xml xml
set #xml =
'<NewProgressReportResult xmlns="http://myDomain.com/crp">
<CrpId>2160</CrpId>
</NewProgressReportResult>'
set #ns = '<root xmlns:ns="http://myDomain.com/crp"/>
exec sp_xml_preparedocument #i output, #xml, #ns
select
CrpId
from openxml (#i, '[ns:NewProgressReportResult]', 2)
with (
[ns:CrpId] int 'CrpId'
)
exec sp_xml_removedocument #i
Related
I'm trying to concatenate string parameters to a sp_executesql statement but I can't find a way to do it. It's quite possible I'm not searched the net worth the right words. What I'm trying to to can be exemplified with the following code, where I want the sp_executesql statement to give the same result as my first print statement (print(#t1 + #t2):
declare #r nvarchar(max), #t1 nvarchar(2), #t2 nvarchar(2)
set #t1 = 'AA'
set #t2 = 'BB'
print(#1 + #t2)
set #r = 'print(#t)'
exec sp_executesql #r, N'#t nvarchar(100)', #t = ?
I've tried:
#t = #t1 + #t2
and
#t = concat(#t1, #t2)
My first question: Is this even possible (I guess it is)? In real this is about making adjustments and som calculation on multiple tables. The table names is built up in three parts; prefix, name and suffix. The databases involved and part of the table names change in different ways for every iteration. In this particular case the first iteration is with one database and one table. The second iteration the database is changed and so the table name. The third iteration is with the same database as the second iteration, the same prefix and name, but with a different suffix and so on. This is solved with variables for the different parts of the table names which is concatenated to a "database.schema.table name" for every iteration.
My second question: How should the code be written for this to work (if it's possible)?
Like others, I am still not sure what you are trying to do here, but at a guess, I'll suggest trying it like this:
declare #r nvarchar(max), #t1 nvarchar(2), #t2 nvarchar(2)
set #t1 = 'AA'
set #t2 = 'BB'
declare #t nvarchar(max)
set #t = #t1 + #t2 -- <-- added this
print(#t1 + #t2)
set #r = 'print(#t)'
exec sp_executesql #r, N'#t nvarchar(100)', #t = #t -- <-- and this
I have a field in my database called filename - it will always follow this format -
[BatchId][CompanyId][FinancialPeriod]
An example would be
001_100_201710
What I would like to do is from that string of text take the [BatchId] so whatever is before the first under score and update another field called Batch in the database. Not sure how to just get the Batch Id.
Thanks in advance
You can split using something like this
DECLARE #filename as varchar(100)
set #filename = '001_100_201710'
DECLARE #index INT
set #index = CHARINDEX('_', #filename)
select SUBSTRING(#filename, 0, #index ) BatchId
I'm receiving an error:
Conversion failed when converting the varchar value 'INSERT INTO TableRowCount (IntFieldID, DecimalField) SELECT 'to data type int"
Using the following code:
DECLARE #start INT -- #start is an INT
SET #start = 1 -- INT
DECLARE #sql NVARCHAR(MAX)
SET #sql = 'INSERT INTO TableRowCount (IntFieldID, DecimalField)
SELECT ' + #start +', COUNT(*)
FROM dbo.somewhere' -- location is irrelevant
EXECUTE(#sql) -- this is where it fails
If I remove IntFieldID and the #start, it will work with an insert (though it defeats the purpose). I've tried including a SELECT CAST(' + #start + ' AS INT), which seems a little redundant since #start is an INT already (casting an INT as an INT), but that doesn't work either. I also tried beginning with an N' DYNAMIC-SQL, which didn't work, I tried using three ''' around everything (didnt' work), and in a few places that I read online, responses suggested putting the variable in the string, which generated the error:
Must declare scalar variable #start
(no surprise, as that didn't sound correct).
A better way than trying to concatenate an integer is to pass it in as a strongly-typed parameter:
DECLARE #start INT = 1;
DECLARE #sql NVARCHAR(MAX) = N'INSERT ...
SELECT #start, COUNT(*) FROM ' + #conn;
EXEC sp_executesql #sql, N'#start INT', #start;
You need to convert your #Start to a varchar.
DECLARE #sql NVARCHAR(MAX)
SET #sql = 'INSERT INTO TableRowCount (IntFieldID, DecimalField)
SELECT ' + CAST(#start as nvarchar(20)) +', COUNT(*)
FROM ' + #conn
SQL Server implicitly converts between datatypes on concatenation or addition based on some fairly complex criteria. Suffice to say if you try to combine an int and a string it will always attempt to convert the string to an int unless you tell it otherwise explicitly.
Below is a conversion chart for your reference from MSDN.
In SQL Server 2008 (TSQL), I've created a stored procedure like this:
CREATE PROCEDURE SP_1_10_2
AS
declare #mostValuableBook nvarchar(255)
SELECT #mostValuableBook = Name
FROM books
WHERE price =
( SELECT MAX(price)
FROM books
WHERE izd LIKE '%BHV%' );
return #mostValuableBook
GO
But, when I'm trying to execute it:
declare #x nvarchar(255)
EXECUTE #x = SP_1_10_2;
SELECT 'The most expensive BHV book:', #x AS 'Name'
GO
I'm getting an error:
Conversion failed when converting the nvarchar value 'Internet
Explorer 3 original' to data type int.
It seems like the problem is in the line
EXECUTE #x = SP_1_10_2;
Can you please tell me what's wrong? Why is it trying to convert to int?
RETURN cannot be used to return nvarchar / varchar such as you have. RETURN is used to return an integer, this can be expressed as some sort of status code 1=True / 0=False. Read more about return here: http://msdn.microsoft.com/en-us/library/ms174998.aspx
In your case, you simply need to use OUTPUT variables which is similiar to pass-by-ref in C# or C++. You pass the variable to the sproc, the sproc modifies it, and you get the expected results after a SELECT....
Change it so that your parameters becomes an output parameter:
CREATE PROCEDURE SP_1_10_2
#mostValueableBook nvarchar(255) output
AS
SELECT #mostValuableBook = Name
FROM books
WHERE price =
( SELECT MAX(price)
FROM books
WHERE izd LIKE '%BHV%' );
SELECT #mostValuableBook
GO
Call it like so:
DECLARE #theValBook nvarchar(255)
EXECUTE SP_1_10_2 #mostValuableBook = #theValBook output
Then you can say:
SELECT 'Most expensive book is', #theValBook
You can also create a function to return the value you desire instead of relying on numeric return codes. SQL Functions come in quite handy. See example below which returns the last name with the highest client id using the LIKE operator
Use MYDB
GO
CREATE Function fn_LastClientIdByName
(
#nameLike NVARCHAR(10)
)
RETURNS NVARCHAR(100)
AS
BEGIN
DECLARE #result nvarchar(100)
DECLARE #clientName NVARCHAR(100)
SELECT top 1 #clientName = [clientLast] + ' ' + [clientFirst]
FROM [dbo].[duiClientOnly]
WHERE clientLast like #nameLike + '%'
order by clid desc
select #result = #clientName
return #result
END
Basically I want to use PRINT statement inside a user defined function to aide my debugging.
However I'm getting the following error;
Invalid use of side-effecting or time-dependent operator in 'PRINT'
within a function.
Can this not be done?
Anyway to aid my user defined function debugging?
Tip:
generate error.
declare #Day int, #Config_Node varchar(50)
set #Config_Node = 'value to trace'
set #Day = #Config_Node
You will get this message:
Conversion failed when converting the varchar value 'value to trace'
to data type int.
No, sorry. User-defined functions in SQL Server are really limited, because of a requirement that they be deterministic. No way round it, as far as I know.
Have you tried debugging the SQL code with Visual Studio?
I got around this by temporarily rewriting my function to something like this:
IF OBJECT_ID ('[dbo].[fx_dosomething]', 'TF') IS NOT NULL
drop function [dbo].[fx_dosomething];
GO
create FUNCTION dbo.fx_dosomething ( #x numeric )
returns #t table (debug varchar(100), x2 numeric)
as
begin
declare #debug varchar(100)
set #debug = 'printme';
declare #x2 numeric
set #x2 = 0.123456;
insert into #t values (#debug, #x2)
return
end
go
select * from fx_dosomething(0.1)
I have tended in the past to work on my functions in two stages. The first stage would be to treat them as fairly normal SQL queries and make sure that I am getting the right results out of it. After I am confident that it is performing as desired, then I would convert it into a UDF.
Use extended procedure xp_cmdshell to run a shell command. I used it to print output to a file:
exec xp_cmdshell 'echo "mytextoutput" >> c:\debuginfo.txt'
This creates the file debuginfo.txt if it does not exist. Then it adds the text "mytextoutput" (without quotation marks) to the file. Any call to the function will write an additional line.
You may need to enable this db-server property first (default = disabled), which I realize may not be to the liking of dba's for production environments though.
No, you can not.
You can call a function from a stored procedure and debug a stored procedure (this will step into the function)
On my opinion, whenever I want to print or debug a function. I will copy the content of it to run as a normal SQL script. For example
My function:
create or alter function func_do_something_with_string(#input nvarchar(max)) returns nvarchar(max)
as begin
-- some function logic content
declare #result nvarchar(max)
set #result = substring(#input , 1, 10)
-- or do something else
return #result
end
Then I just copy and run this out of the function to debug
declare #input nvarchar(max) = 'Some string'
-- some function logic content
declare #result nvarchar(max)
set #result = substring(#input , 1, 10)
-- this line is added to check while debugging
print #result
-- or do something else
-- print the final result
print #result
You can try returning the variable you wish to inspect.
E.g. I have this function:
--Contencates seperate date and time strings and converts to a datetime. Date should be in format 25.03.2012. Time as 9:18:25.
ALTER FUNCTION [dbo].[ufn_GetDateTime] (#date nvarchar(11), #time nvarchar(11))
RETURNS datetime
AS
BEGIN
--select dbo.ufn_GetDateTime('25.03.2012.', '9:18:25')
declare #datetime datetime
declare #day_part nvarchar(3)
declare #month_part nvarchar(3)
declare #year_part nvarchar(5)
declare #point_ix int
set #point_ix = charindex('.', #date)
set #day_part = substring(#date, 0, #point_ix)
set #date = substring(#date, #point_ix, len(#date) - #point_ix)
set #point_ix = charindex('.', #date)
set #month_part = substring(#date, 0, #point_ix)
set #date = substring(#date, #point_ix, len(#date) - #point_ix)
set #point_ix = charindex('.', #date)
set #year_part = substring(#date, 0, #point_ix)
set #datetime = #month_part + #day_part + #year_part + ' ' + #time
return #datetime
END
When I run it.. I get:
Msg 241, Level 16, State 1, Line 1
Conversion failed when converting date and/or time from character string.
Arghh!!
So, what do I do?
ALTER FUNCTION [dbo].[ufn_GetDateTime] (#date nvarchar(11), #time nvarchar(11))
RETURNS nvarchar(22)
AS
BEGIN
--select dbo.ufn_GetDateTime('25.03.2012.', '9:18:25')
declare #day_part nvarchar(3)
declare #point_ix int
set #point_ix = charindex('.', #date)
set #day_part = substring(#date, 0, #point_ix)
return #day_part
END
And I get '25'. So, I am off by one and so I change to..
set #day_part = substring(#date, 0, #point_ix + 1)
Voila! Now it works :)