Extract data matching a condition inside an XML array in SQL server - sql

Considering this simple table id (int), name (varchar), customFields (xml)
customFields contains an XML representation of a C# Dictionary. E.g :
<dictionary>
<item>
<key><int>1</int></key>
<value><string>Audi</string></value>
</item>
<item>
<key><int>2</int></key>
<value><string>Red</string></value>
</item>
</dictionary>
How do I select all rows of my table with 3 columns: id, name and 1 column that is the content of the string tag where the value of the int tag is equal 1.
The closest to the result I managed to get is:
SELECT id, name, C.value('(value/string/text())[1]', 'varchar(max)')
FROM myTable
OUTER APPLY customFields.nodes('/dictionary/item') N(C)
WHERE (customFields IS NULL OR C.value('(key/int/text())[1]', 'int') = 1)
Problem is, if xml doesn't have a int tag = 1 the row is not returned at all (I would still like to get a row with id, name and NULL in the 3rd column)

I've created a table the same as yours and this query worked fine:
select id, name,
(select C.value('(value/string/text())[1]','varchar(MAX)')
from xmlTable inr outer apply
customField.nodes('/dictionary/item') N(C)
where
C.value('(key/int/text())[1]','int') = 1
and inr.id = ou.id) as xmlVal
from xmlTable ou
Here is my result:
The reason why your query didn't worked is because it first selects values of "value/string" for all rows from "myTable" and then filters them. Therefore, the null values appear only on empty fields, and on the other fields (which contains any xml value), the "value/string/text()" is displayed. This is what your query without where clause returns:
id,name,xml
1 lol NULL
2 rotfl Audi
2 rotfl Red
3 troll Red

Related

Getting values from array of objects jsonb postgresql

I am storing some ids and names in a jsonb array of object like this
[{"id":"1","name":"abc"},{"id":"2","name":"cde"}]
My table looks like this
id userinfo
1 [{"id":"1","name":"abc"},{"id":"2","name":"cde"}]
2 [{"id":"3","name":"fgh"},{"id":"4","name":"ijk"}]
I am trying to select all the records with id 1 but I just want to get ids in userinfo object I don't want names
I tried this
select distinct userinfo->'name' from table where id = 1
but this is giving me null value
This will work with this query
select distinct userinfo->0->'name' from table where id = 1
but I don't know the index so how can I use this query to get my desired result
Thanks
You need to normalize the data by unnesting the array, then you can access each element.
select ui.info ->> 'id' as id,
ui.info ->> 'name' as name
from the_table t
cross join lateral jsonb_array_elements(t.userinfo) as ui(info)
where t.id = 1;
Online example: http://rextester.com/FCNM11312

obtain data from table 2 using reference of table 1 [sql-server]

[TRN_ID] is the id of another table, how to get the data from that table and show this data in the xml output
SELECT TOP (1) [ECB_ID] as Id
,[ECB_PASSWORD_GENERATED] as clave
,[ECB_CONSECUTIVE_NUMBER] as consecutive
,[ECB_BILL_DATE] as date
,[TRN_ID] <- id of other table
,[QRC_ID]
FROM [crdx_COREDev1].[dbo].[ECB_ELECTRONICBILL]
FOR XML PATH ('FE')
example of output
<FE>
<id>1</id>
<pass>0</pass>
<CONSECUTIVE>0</CONSECUTIVE>
....
--These are the data from the other table.
<emisor>
<name>1</name>
<Copany>myCompa</Company>
...
...
</emisor>
</FE>
In summary, I have a table 1 with different data, some of those data are references to other tables, using that reference I want to obtain the data from table 2
You can use a nested FOR XML linked to your TRN_ID.
SELECT TOP (1)
[ECB_ID] as Id,
[ECB_PASSWORD_GENERATED] as clave,
[ECB_CONSECUTIVE_NUMBER] as consecutive,
[ECB_BILL_DATE] as date,
[TRN_ID],
[QRC_ID],
(
SELECT
N.YourWantedColumn
FROM
YourOtherTable AS N
WHERE
E.TRN_ID = N.TRN_ID -- I'm guessing it's called N.TRN_ID
FOR XML
PATH ('emisor'), TYPE
)
FROM
[crdx_COREDev1].[dbo].[ECB_ELECTRONICBILL] AS E
FOR XML
PATH ('FE')

Sqlite fetch from table

I have a table named Text_Field which consists of a column named ID,
I have another table named Content which consists of a table named value,
I want to fetch those values of ID from the Text_Field table which are present in the value column of the Content and satisfying a said condition.
I know I can construct a query like this
SELECT ID
FROM Text_Field
WHERE ID IN (
SELECT value
FROM CONTENT
WHERE USER='CURRENT_USER')
My only problem is that for some scenarios the value table might contain the ID inside a string
So the inner query might return something like
56789
12334
12348
Rtf(833405)
Now if my ID is 833405 it is present in the value column but the IN query would return false,
I tried
group_concat(value)
So that the inner query returns a single row which is a string,
56789,12334,12348,Rtf(833405)
I want to know that after group_concat can I use something as LIKE to satisfy my need
Or is there some other way I can do this?
Use exists instead, with like:
SELECT t.ID
FROM Text_Field t
WHERE EXISTS (SELECT 1
FROM CONTENT c
WHERE c.USER = 'CURRENT_USER' AND
(c.value = t.id OR
c.value LIKE '%(' || t.id || ')%'
)
);
Note:

how to extract data from xml having multiple nodes which are same under a parent node into a table in sql

I have a xml like
<list of roleids>
<roleid> 1 </roleid>
<roleid> 2 </roleid>
<roleid> 3 </roleid>
<roleid> 4 </roleid>
</list of Roleids>
I want the roleid values in a table with column RoleID
I have tried with the below query but i am not getting the expected output
declare #ListOfRoleID XML
set #ListOfRoleID =
'<list>
<roleid>1</roleid>
<roleid>2</roleid>
</list>'
DECLARE #RoleIDList TABLE (RoleID int)
INSERT INTO #RoleIDList(RoleID)
SELECT X1.value('(roleid)[1]','INT') as roleid
from #ListOfRoleID.nodes('/list') as ListOfRoleID(x)
CROSS APPLY #RoleIDList.nodes('/list') AS ListOfRoleID1 (X1)
You want to project .nodes('/list/roleid'), which will create one row per roleid. Then extract the value. No need for cross apply. See sqlfiddle:
declare #ListOfRoleID XML = '<list>
<roleid>1</roleid>
<roleid>2</roleid>
<roleid>3</roleid>
</list>';
SELECT x.value('.','INT') as roleid
from #ListOfRoleID.nodes('/list/roleid') as ListOfRoleID(x);

Updating SQL table from XML

I am using InfoPath 2007 to send out a survey (it is not connected to SharePoint or a DataBase). The file I will get back is an XML file. Every place there is an answer block, it has its own unique id (aka field name).
Now, I have a SQL Server Database (2007?) with a table "Responses". Its columns are: AnswerID(unique PK), QuestionID (FK) (which is the unique id (field name), and Answer. The QuestionID is already populated with the unique id (field name). There are more than 300 records for QuestionID.
What I need to be able to do is reach into the XML file, find the QuestionID (field name), grab the data for that field name, and then put the data into the DB column "Answer" that matches the field name in the QuestionID column.
Is there an easy/medium way to do this mapping/updating with the least amount of chance of error?
NOTE: I tried to use the DB import XML data wizard, the information breaks out into an unmanageable number of tables.
You can shred the XML into rows and columns and then use that to update your table.
Here is a little example of what you can do.
create table Responses(QuestionID varchar(10), Answer varchar(10))
insert into Responses values('Q1', null)
insert into Responses values('Q2', null)
insert into Responses values('Q3', null)
declare #xml xml
set #xml =
'<root>
<question ID="Q1">Answer1</question>
<question ID="Q2">Answer2</question>
<question ID="Q3">Answer3</question>
</root>'
;with cte as
(
select
r.n.value('#ID', 'varchar(10)') as QuestionID,
r.n.value('.', 'varchar(10)') as Answer
from #xml.nodes('/root/*') as r(n)
)
update R
set Answer = C.Answer
from Responses as R
inner join cte as C
on R.QuestionID = C.QuestionID
select *
from Responses
Result:
QuestionID Answer
---------- ----------
Q1 Answer1
Q2 Answer2
Q3 Answer3
The XML I used most certainly does not look anything like what you have but it should give you a hint of what you can do. If you post a sample of your XML file, table structure and expected result/output you can probably get a more precise answer.
Edit
declare #xml xml =
'<?xml version="1.0" encoding="UTF-8"?>
<my:myFields xmlns:my="xx.com" xml:lang="en-us">
<my:group1>
<my:group2>
<my:field1>Im an analyst.</my:field1>
<my:group3>
<my:group4>
<my:field2>1</my:field2>
<my:field3>I click the mouse.</my:field3>
</my:group4>
<my:group4>
<my:field2>2</my:field2>
<my:field3>I type on the keyboard.</my:field3>
</my:group4>
</my:group3>
</my:group2>
<my:group2>
<my:field1>Im a stay at home mom.</my:field1>
<my:group3>
<my:group4>
<my:field2>1</my:field2>
<my:field3>I Cook.</my:field3>
</my:group4>
<my:group4>
<my:field2>2</my:field2>
<my:field3>I clean.</my:field3>
</my:group4>
</my:group3>
</my:group2>
</my:group1>
</my:myFields>'
;with xmlnamespaces('xx.com' as my)
select
T.N.value('../../my:field1[1]', 'varchar(50)') as Field1,
T.N.value('my:field2[1]', 'varchar(50)') as Field2,
T.N.value('my:field3[1]', 'varchar(50)') as Field3
from #xml.nodes('my:myFields/my:group1/my:group2/my:group3/my:group4') as T(N)
Result:
Field1 Field2 Field3
Im an analyst. 1 I click the mouse.
Im an analyst. 2 I type on the keyboard.
Im a stay at home mom. 1 I Cook.
Im a stay at home mom. 2 I clean.