Code:
DECLARE #dataxml XML = CONVERT(xml ,'<Parentnode><childnode><id>1</id></childnode></Parentnode>')
DECLARE #childnode VARCHAR(50)
SET #childnode = (SELECT DISTINCT
r.value('fn:local-name(.)', 'nvarchar(50)') as t
FROM #dataxml.nodes('//Parentnode/*') AS records(r))
SELECT #childnode
SELECT
t.value('id[1]', 'int') AS id
FROM
#dataxml.nodes('/Parentnode/*[local-name(.)=sql:variable("#childnode")]/*') AS XD(t)
Output is returned as NULL, but it should comes with id value in xml
What's wrong in this code?
You just need to remove the /* characters at the end of your last line, like this:
#dataxml.nodes('/Parentnode/*[local-name(.)=sql:variable("#childnode")]') AS XD(t)
Also I had to remove the $ character at the end of the FROM keyword, but I'm guessing that could just be a typo. I tested this is SQL Server 2012.
Related
I am writing a stored procedure to get a particular value.
declare #num int
set #num = (SELECT Id
FROM [sometable]
WHERE Name like '%today%')
-- returns #num = 1
Select Value
FROM [anothertable]
where name like 'days1'
In the last line of the query I want to add "1" or any other number after 'days', depending on the variable #num.
How can I do it, sort of like how we use template literals in Javascript, using the ${} syntax but in SQL?
You can just use the first query as a sub-query of the second:
select [Value]
from anothertable
where [name] = Concat('days', (select Id from sometable where [Name] like '%today%'));
I am looking to get an order number from a column named KEY_Ref, this ref column have various contents, but some rows look like this
LINE_NO=15^ORDER_NO=176572^RELEASE_NO=1^
Now I am interested in getting the value for ORDER_NO (176572 in this case)
How would I (In SQL Server) go about getting this (Or other) value from the main string
The logic is always
key1=value1^key2=value2^key3=value3^
You can use string_split():
select t.*, s.orderno
from t outer apply
(select stuff(s.value, 1, 9, '') as orderno
from string_split(t.key_ref, '^') s
where s.value like 'ORDER_NO=%'
) s;
Here is a db<>fiddle.
this is going to be a bit lengthy answer however if your SQL server version doesn't support string_split function you may use this.
declare #str varchar(100) = 'LINE_NO=15^ORDER_NO=176572^RELEASE_NO=1^'
declare #substr1 varchar(50) = substring(#str,charindex('^',#str)+1,len(#str))
declare #substr2 varchar(50) = substring(#substr1,charindex('=',#substr1)+1,charindex('^',#substr1)-charindex('=',#substr1)-1)
select #substr2 as 'order number'
the final variable will produce the desired value and you must merge the above queries to a single query that can fetch the value from the table in a single select statement.
this will work only if the pattern doesn't deviate from the one you've mentioned.
I have 2 tables - Table A with primary key column of type binary(16) and another table B with foreign key referring to the same column but with data type as varchar(50). So table A has values like 0x0007914BFFEC4603A6900045492EFA1A and table B has the same value stored as 0007914BFFEC4603A6900045492EFA1A.
How do i compare these 2 columns, which would give me
0007914BFFEC4603A6900045492EFA1A = 0x0007914BFFEC4603A6900045492EFA1A
You will need to convert the binary(16) to a string. A sample of how to do this can be found in the question below. This question converts a varbinary to a string, but the same technique can be used for a binary column or variable:
SQL Server converting varbinary to string
Example code for how to do this is below:
declare #bin binary(16), #str varchar(50)
set #bin = 0x0007914BFFEC4603A6900045492EFA1A
set #str = '0007914BFFEC4603A6900045492EFA1A'
select #bin as'binary(16)', #str as 'varchar(50)'
-- the binary value is not equal to the string value
-- this statement returns 'binary value is not equal to string'
if #bin = #str select 'binary value is equal to string'
else select 'binary value is not equal to string'
declare #binstr varchar(50)
select #binstr = convert(varchar(50), #bin, 2)
select #binstr
-- the converted string value matches the other string
-- the result of this statement is "converted string is equal"
if #binstr = #str select 'converted string is equal'
else select 'converted string is NOT equal'
To use this in a join, you can include the conversion in the ON clause of the inner join or in a WHERE clause:
select *
from TableA
inner join TableB
on TableB.char_fk = convert(varchar(50), TableA.bin_pk, 2)
UPDATE
For SQL Server 2005, you can use an XML approach shown by Peter Larsson here:
-- Prepare value
DECLARE #bin VARBINARY(MAX)
SET #bin = 0x5BAA61E4C9B93F3F0682250B6CF8331B7EE68FD8
-- Display the results
SELECT #bin AS OriginalValue,
CAST('' AS XML).value('xs:hexBinary(sql:variable("#bin"))', 'VARCHAR(MAX)') AS ConvertedString
You can also use the undocumented function sys.fn_varbintohexstr, but as this post on dba.stackexchange.com explains, there are several reasons why you should avoid it.
CONVERT with style 2 to get a binary representation of the hexadecimal string;
... where TableA.bin_pk = CONVERT(VARBINARY, TableB.char_fk, 2)
The correct aproach is to set both fields in the same datatype. in order to to do this create a new table say temp and use select into and convert:
select field1,...,convert(varchar(50),varbinary(16),fieldToConvert)...,fieldN
into myNewTable
Found the answer. I need to use
master.dbo.fn_varbintohexstr (#source)
which converts a varbinary to varchar, and then works perfectly well for comparison in my scenario.
SELECT #Name = Name FROM Table FOR XML AUTO
Does not work, how do you get the XML result from using FOR XML into a variable?
This will work:
SELECT #Name = CONVERT(XML, (
SELECT Name
FROM SomeTable
FOR XML AUTO
));
You can try it without the wrapping CONVERT(XML, (...)) statement but I've found that SQL Server doesn't like assigning to XML variables without that explicit cast.
I'm trying to query a table with a column which is xml data with the query and value functions. When using regular string literals it's all okay, but if I put that in a stored procedure and try to use variables it doesn't work.
I suppose I'm not using the correct datatype, but after some searching I can't figure out what datatype the query function wants.
Example:
table contains
| Id | xmldata |
| 1 | <data><node>value</node></data> |
now, using the select query
select id
from table
where xmldata.query('/data/node').value('.', 'VARCHAR(50)') = 'value'
gets me the data I want. But, if I use this in a stored procedure and use a parameter #xpath varchar(100) and pass that to the query method as xmldata.query(#xpath)
i get the error
The argument 1 of the xml data type method "query" must be a string literal.
I guess varchar(100) is not correct, but what datatype can I use that would make MSSQL happy?
Update:
Okay, so. Apparently you can't pass a parameter to the query method "just like that", but one can use the sql:variable in conjunction with local-name to work a part of it out. So, for instance, this will work
declare #xpath VarChar(100)
set #xpath='node'
select objectData.query('/data/*[local-name() = sql:variable("#xpath")]')
.value('.', 'varchar(100)') as xmldata
from table
and value is selected in the column xmldata. But(!) it requires that the root node is the first value in the query function. The following will not work
declare #xpath VarChar(100)
set #xpath='/data/node'
select objectData.query('*[local-name() = sql:variable("#xpath")]')
.value('.', 'varchar(100)') as xmldata
from table
notice how the query path is "moved up" to the variable. I will continue my investigations..
A literal is the opposite of a variable. The message means that you cannot pass a variable as the first argument to query.
One way around that is dynamic SQL:
declare #sql varchar(max)
set #sql = 'select id from table where xmldata.query(''' + #path +
''').value(''.'', ''VARCHAR(50)'') = ''value'''
exec #sql
As you can see, dynamic SQL does not result in very readable code. I would certainly investigate alternatives.
EDIT: Your suggestion of local-name() works for node names.
declare #nodename varchar(max)
set #nodename = 'node'
...
where xmldata.query('//*[local-name()=sql:variable("#nodename")]')
.value('.', 'varchar(50)') = 'value'
There doesn't seem to be an equivalent for paths.