XML structure:
<ns0:message xmlns:ns0='xxx:testing'>
<ns0:field name='AAA'>...</ns0:field>
<ns0:field name='BBB'>...</ns0:field>
<ns0:field name='VVV'>...</ns0:field>
<ns0:field name='CAR'>...</ns0:field>
</ns0:message>
I have SQL that will extract the values of the attributes titled name:
SELECT
( (SELECT ',' + CHAR(13) + P.N.value('#name', 'varchar(max)')
FROM myTable.message_xml.nodes('declare namespace ns0="xxx:testing";
ns0:message/ns0:field[ #name = "AAA" or
#name = "BBB"]') P(N)
FOR XML PATH(''), type).value('substring(text()[1], 3)', 'varchar(max)')) as ATTRIBUTE_VALUES
This returns a column that looks like:
ATTRIBUTE_VALUES
---------------
AAA,
BBB
My problem is that the list of potential attribute values is quite large.
Instead of repeating #name = "AAA" in my query for every attribute value I want to check for, I was hoping I could declare it as a variable like:
DECLARE #ATTRIBUTES VarChar(Max)
SET #ATTRIBUTES = '(AAA,BBB,CAR,XYZ)'
And then just stick the variable in the sql like:
[#name = sql:variable("#ATTRIBUTES")]
but this is not working for any combination of parens,commas,etc I use to build the variable.
You can use contains function.
Declare a variable like so:
DECLARE #ATTRIBUTES VarChar(Max) = '|AAA|BBB|CAR|XYZ|';
And in you query instead of #name = "AAA" use:
contains(sql:variable("#ATTRIBUTES"), concat("|", #name, "|"))
Related
My table has column names m1,m2,m3...,m12.
I'm using iterator to select them and insert them one by one in another table.
In this iterator I'm trying to generate filed names with:
'['+concat('m',cast(#P_MONTH as nvarchar))+']'
where #P_MONTH is incrementing in each loop.
so for #P_MONTH = 1 this suppose to give [m1] which works fine.
But when I run query I get:
Conversion failed when converting the nvarchar value '[m1]' to data
type int.
And if I put simply [m1] in that select it works ok.
How to concat filed name so it can be actually interpreted as filed name from certain table?
EDIT
Here is full query:
DECLARE #SQLString nvarchar(500),
#P_YEAR int,
#P_MONTH int = 1
set #P_YEAR = 2018
WHILE #P_MONTH < 13
BEGIN
SET #SQLString =
'INSERT INTO [dbo].[MASTER_TABLE]
(sector,serial,
date, number, source)'+
'SELECT ' + '[SECTOR],[DEPARTMENT]' +
QUOTENAME(cast(CONVERT(datetime,CONVERT(VARCHAR(4),#P_YEAR)+RIGHT('0'+CONVERT(VARCHAR(2),#P_MONTH),2)+'01',5) as nvarchar))+
QUOTENAME ('M',cast(#P_MONTH as nvarchar)) +
'EMPLOYED' +
'FROM [dbo].[STATS]'+
'where YEAR= #P_YEAR'
EXECUTE sp_executesql #SQLString
SET #P_MONTH = #P_MONTH + 1
END
It's still not working. It executes successfully but it does nothing.
Good day,
Let's create a simple table for the sake of the explanation
DROP TABLE IF EXISTS T
GO
CREATE TABLE T(a1 INT)
GO
INSERT T(a1) VALUES (1),(2)
GO
SELECT a1 FROM T
GO
When we are using a query like bellow, the server parse the text as a value and not as a column name
DECLARE #String NVARCHAR(10)
SELECT #String = '1'
--
SELECT '['+concat('a',cast(#String as nvarchar))+']'
FROM T
GO
This mean that the result will be 2 rows with no name for the column and the value will be "[a1]"
Moreover, the above query uses the brackets as part of the string.
One simple solution is to use the function QUOTENAME in order to add brackets around a name.
Another issue in this approach is the optional risk of SQL Injection. QUOTENAME might not be perfect solution but can help in this as well.
If we need to use entities name dynamically like in this case the column name then for most cases using dynamic query is the best solution. This mean to use the Stored Procedure sp_executesql as bellow
DECLARE #String INT
SELECT #String = 1
DECLARE #SQLString nvarchar(500);
SET #SQLString =
'SELECT ' + QUOTENAME(concat('a',cast(#String as nvarchar))) + ' FROM T'
EXECUTE sp_executesql #SQLString
GO
I wants to separate string by comma. Actually I wants to filter in WHERE Clause like
CREATE PROC spGetRecords
#class varchar(50)
AS
BEGIN
SELECT *
FROM SampleTable
WHERE class in (#class) --in Database class is an integer
END
So, I want to pass the parameter when execute query like below
spGetRecords #class = '12,22,45,66'
I think it's not possible to pass multiple value in single parameter in my case.
So, If I remove separate the string by ',' then I can run my query in while loop that will bring the record correct?
So, How can I separate the string by comma
You can try splitting using xml path as below:
Declare #delimiter nvarchar(max) = ','
Declare #str nvarchar(max) = '12,22,45,66'
Declare #xml as xml
Select #xml = CAST('<x>' + REPLACE((SELECT REPLACE(#str,#delimiter,'$$$SSText$$$') AS [*] FOR XML PATH('')),'$$$SSText$$$','</x><x>')+ '</x>' AS XML)
--select #xml
Select y.value(N'text()[1]', N'nvarchar(MAX)') as value
FROM #xml.nodes(N'x') as x(y)
If you are in SQL Server >= 2016 you can use STRING_SPLIT() as below:
Select * from string_split('12,22,45,66',',')
Use dynamic SQL
exec 'SELECT * FROM SampleTable WHERE class in (' + #class + ')'
which will patch the strings together and then execute it like this:
SELECT * FROM SampleTable WHERE class in (12,22,45,66)
Here is a good solution - Converting String List into Int List in SQL . Idea here is to send in an int list to a stored procedure as an XML parameter.
Here is another quick but dirty solution - t-sql Convert comma separated string into int, without using user created function . Here the passed in value is used within a dynamic sql statement.
More ideas - http://sql-articles.com/scripts/function-to-split-comma-separated-string-to-integer/
I am trying to do this:
JSON_VALUE(#jsondata, CONCAT('$.[', #count, '].Name')
such that I can reference a value in my json list using a variable, however the JSON_VALUE function requires a string literal for the 2nd argument (JSON Path).
Is there a way to either make the function read a string as a string literal, or another way to reference a list with a variable?
Thanks.
You can address a list with a variable by destructuring it into a table using OPENJSON.
For example, given:
declare #jsondata nvarchar(max) = '[
{"Name":"zero","Value":"cero"},
{"Name":"one","Value":"uno"},
{"Name":"two","Value":"dos"},
{"Name":"three","Value":"tres"}
]'
declare #count int set #count = 1
declare #val nvarchar(50)
set #val = (select JSON_VALUE(value, '$.Name') from OPENJSON(#JsonData) d where d."key" = #count)
select #count, #val
For a more advanced method you can query JSON with a schema that describes the structure and elements you are interested in:
https://learn.microsoft.com/en-us/sql/relational-databases/json/use-openjson-with-an-explicit-schema-sql-server
I have a problem! We have an SQL Server table that has an XML type column. This column have a number of nodes and some of them have misspelled values.
I would like to write a script which updates all occurrences of this misspelling! The problem is I don't know how to do it!
Let's say that one of the nodenames in the XML column is TEST and some of these nodes have the misspelled value MISSPELLED and I want it to be modified to CORRECT after the update.
Is this possible to do and if so how?
Thanks in advance.
/Kaunda
<REF><Person><FirstName>John</FirstName><LastName>Smith</LastName><System><User><Systemid>System1</Systemid><Type>UserId</Type><Useridentity>Userid1</Useridentity></User><User><Systemid>System2</Systemid><Type>UserIdx</Type><Useridentity>Userid2</Useridentity></User><User><Systemid>System2</Systemid><Type>Department</Type><Useridentity>Finance</Useridentity></User><User><Systemid>System3</Systemid><Type>UserId</Type><Useridentity>Userid3</Useridentity></User><User><Systemid>System4</Systemid><Type>UserIdx</Type><Useridentity>Userid4</Useridentity></User></System></Person></REF>
You can modify XML column data by following way :
CREATE TABLE Test (C1 XML)
INSERT INTO Test
VALUES ('<REF>
<Person>
<FirstName>John</FirstName>
<LastName>Smith</LastName>
<System>
<User><Systemid>System1</Systemid><Type>UserId</Type><Useridentity>Userid1</Useridentity></User>
<User><Systemid>System2</Systemid><Type>UserIdx</Type><Useridentity>Userid2</Useridentity></User>
<User><Systemid>System2</Systemid><Type>Department</Type><Useridentity>Finance</Useridentity></User>
<User><Systemid>System3</Systemid><Type>UserId</Type><Useridentity>Userid3</Useridentity></User>
<User><Systemid>System4</Systemid><Type>UserIdx</Type><Useridentity>Userid4</Useridentity></User>
</System>
</Person>
</REF>
')
UPDATE [Test]
SET C1.modify('replace value of (/REF/Person/System/User/Type/text())[1] with "UserId"')
WHERE C1.value('(/REF/Person/System/User/Type/text())[1]', 'varchar(max)') LIKE '%UserIdx%'
UPDATE :
For multiple values update in column, you need to write script like below :
DECLARE #strSQL NVARCHAR(MAX)
DECLARE #Index INT
DECLARE #NodeCount INT
SET #Index = 1
SELECT #NodeCount = C1.value('count(/REF/Person/System/User/Type)', 'INT') from Test
WHILE #Index <= #NodeCount
BEGIN
SET #strSQL = ' UPDATE [Test]
SET C1.modify(''replace value of (/REF/Person/System/User/Type/text())[' + CAST(#Index AS VARCHAR(10)) + '] with "UserId"'')
WHERE C1.value(''(/REF/Person/System/User/Type/text())[' + CAST(#Index AS VARCHAR(10)) + ']'', ''varchar(max)'') LIKE ''%UserIdx%'''
EXEC(#strSQL)
SET #Index = #Index + 1
END
I am trying to retrieve an XML attribute from an XML variable passing in the name of the desired attribute. The first select statement works just fine retrieving the correct attribute values. However, when I try to set within a SQL variable the desired attribute name, all that is displayed is the string /root/attribs/#id instead of the actual value. I have tried numerous permutations of the #path variable, all to no avail.
What am I missing here?
DECLARE #XMLString XML = '<root><attribs flags="1" id="test_id" platform="test_platform" /></root>';
SELECT
flags = x.c.value('(/root/attribs/#flags)[1]', 'nvarchar(50)') ,
id = x.c.value('(/root/attribs/#id)[1]', 'nvarchar(50)') ,
[platform] = x.c.value('(/root/attribs/#platform)[1]', 'nvarchar(50)')
FROM
#XMLString.nodes('/*') x ( c );
DECLARE #Path NVARCHAR(50) = '/root/attribs/#id';
SELECT
result = x.c.value('(sql:variable("#Path"))[1]', 'nvarchar(50)')
FROM
#XMLString.nodes('/*') x ( c );
This will allow you to specify the attribute name.
DECLARE #XMLString xml = '
<root>
<attribs flags="1" id="test_id" platform="test_platform" />
</root>'
DECLARE #Attribute nvarchar(max) = 'flags'
SELECT
t.x.value('(/root/attribs/#*[local-name() = sql:variable("#Attribute")])[1]', 'nvarchar(max)')
FROM #XMLString.nodes('/*') t(x)