I have a table which contains xml format request.
For eg:
Api_id xmlRequest Sent_Time
1 ........ 07-04-2016 10:07:12:345
1 ........ 08-04-2016 10:03:12:345
2 ........ 09-04-2016 10:08:12:345
2 ........ 09-04-2016 10:09:12:345
For Api_id, we can have multiple request.
XML request schema is same, but has different values.
Xml request is as :
<?xml version="1.0"?>
<!DOCTYPE PARTS SYSTEM "parts.dtd">
<PARTS>
<TITLE>Computer Parts</TITLE>
<PART>
<ITEM>Motherboard</ITEM>
<MANUFACTURER>ASUS</MANUFACTURER>
<MODEL>P3B-F</MODEL>
<COST> 123.00</COST>
</PART>
</PARTS>
I need store procedure, so I can send API_id, and value(which i can search in xml request ) and get xml requests based on Item value.
CREATE PROCEDURE getxmlRequest(
#Api_Id INT
#value
,#xmlRequest VARCHAR(max) out)
AS
BEGIN
Set #xmlRequest = SELECT xmlRequest FROM Api_request
WHERE Api_id = #Api_id
/* here need to iterate over #xmlRequest */
Set #Xmlvalue = SELECT X.R.value ('.','nvarchar (150)')
FROM #xmlRequest.nodes(XPATH) X(R)
if(#XmlValue = #value)
/*Add to result so i can return
/*I want to return all #xmlRequest if we has value from xpath*/
END;
So my question If
Set #xmlRequest = SELECT xmlRequest FROM Api_request
WHERE Api_id = #Api_id
If we will get multiple result : does it possible to iterate? If yes how efficient i can ?
How to return multiple #xmlRequest as Api_id is same?
Does any one work on such kind of scenario? Please help me.
Try this query
SELECT *,CONVERT(XML,xmlRequest,2)
FROM Api_request
WHERE Api_id = #Api_id
AND CONVERT(XML,xmlRequest,2).value('(/PARTS/PART/ITEM)[1]','nvarchar(max)')
LIKE '%'+#value+'%'
It will return all the xmlRequest where contains your value
Your question is quite unclear, but please have look on this:
CREATE TABLE #testTbl(Api_id INT, xmlRequest VARCHAR(MAX), SentTime DATETIME);
INSERT INTO #testTbl VALUES
(1,'<?xml version="1.0"?>
<!DOCTYPE PARTS SYSTEM "parts.dtd">
<PARTS>
<TITLE>Computer Parts</TITLE>
<PART>
<ITEM>Motherboard</ITEM>
<MANUFACTURER>ASUS</MANUFACTURER>
<MODEL>P3B-F</MODEL>
<COST> 123.00</COST>
</PART>
</PARTS>',GETDATE())
,(1,'<?xml version="1.0"?>
<!DOCTYPE PARTS SYSTEM "parts.dtd">
<PARTS>
<TITLE>Computer Parts</TITLE>
<PART>
<ITEM>CPU</ITEM>
<MANUFACTURER>INTEL</MANUFACTURER>
<MODEL>CPUModelXY</MODEL>
<COST>345.00</COST>
</PART>
</PARTS>',GETDATE())
,(2,'<?xml version="1.0"?>
<!DOCTYPE PARTS SYSTEM "parts.dtd">
<PARTS>
<TITLE>Car Parts</TITLE>
<PART>
<ITEM>Wheel</ITEM>
<MANUFACTURER>Pirelli</MANUFACTURER>
<MODEL>WheelModelXY</MODEL>
<COST>100.00</COST>
</PART>
</PARTS>',GETDATE());
This will rerturn all rows where the Api_id=1
SELECT Api_id
,CONVERT(XML,xmlRequest,2) AS xmlRequest
,SentTime
FROM #testTbl
WHERE Api_id=1;
This will return table-like data. You can use "normal" SQL (WHERE, GROUP BY, ...) to continue
DECLARE #Api_Id INT=NULL;
WITH MyRequests AS
(
SELECT Api_id
,RealXML.value('(/PARTS/TITLE)[1]','varchar(max)') AS Title
,part.value('ITEM[1]','varchar(max)') AS Item
,part.value('MANUFACTURER[1]','varchar(max)') AS Manufacturer
,part.value('MODEL[1]','varchar(max)') AS Model
,part.value('COST[1]','decimal(12,4)') AS Cost
,SentTime
FROM #testTbl
CROSS APPLY(SELECT CONVERT(XML,xmlRequest,2) AS RealXML) AS ConvertedToXML
CROSS APPLY RealXML.nodes('/PARTS/PART') AS A(part)
WHERE #ApiId IS NULL OR Api_Id=#Api_Id
)
SELECT *
FROM MyRequests
--WHERE ...
--GROUP BY ...
--ORDER ...
;
The result
+---+----------------+-------------+---------+--------------+----------+-------------------------+
| 1 | Computer Parts | Motherboard | ASUS | P3B-F | 123.0000 | 2016-04-07 11:54:08.980 |
+---+----------------+-------------+---------+--------------+----------+-------------------------+
| 1 | Computer Parts | CPU | INTEL | CPUModelXY | 345.0000 | 2016-04-07 11:54:08.980 |
+---+----------------+-------------+---------+--------------+----------+-------------------------+
| 2 | Car Parts | Wheel | Pirelli | WheelModelXY | 100.0000 | 2016-04-07 11:54:08.980 |
+---+----------------+-------------+---------+--------------+----------+-------------------------+
Clean Up
GO
DROP TABLE #testTbl;
Related
This may look like a duplicate, but what I can find are getting multiple rows from nodes with elements inside, like
<products>
<product>
<image>url1</image>
</product>
<product>
<image>url1</image>
</product>
</products>
What I have is an XML-field in a table (with PLU as an integer)
<product>
<images>
<image>url1</image>
<image>url2</image>
<image>url3</image>
</images>
</product>
I want
image
-----
url1
url2
url3
I tried
select a.image.value('image','nvarchar(max)') as image
from products r
cross apply r.xml.nodes('/product/images') a(image) where PLU='8019'
but that gives
XQuery [products.xml.value()]: 'value()' requires a singleton (or empty sequence),
found operand of type 'xdt:untypedAtomic *'
As I want the value of each node, not of subnodes, I tried
select a.image.value('.','nvarchar(max)') ...
but that gave me only one row with url1url2url3 all urls concatenated.
select a.image.value('image[1]','nvarchar(max)')
gives only url1
PLease try the following solution.
SQL
-- DDL and sample data population, start
DECLARE #tbl TABLE (ID INT IDENTITY PRIMARY KEY, xmldata XML);
INSERT #tbl (xmldata) VALUES
(N'<product>
<images>
<image>url1</image>
<image>url2</image>
<image>url3</image>
</images>
</product>');
-- DDL and sample data population, end
SELECT ID
, c.value('text()[1]','nvarchar(max)') AS image_url
FROM #tbl
CROSS APPLY xmldata.nodes('/product/images/image') AS t(c);
Output
+----+-----------+
| ID | image_url |
+----+-----------+
| 1 | url1 |
| 1 | url2 |
| 1 | url3 |
+----+-----------+
A shorter solution than Yitzhak Khabhinsky is this by Martin Boje Carpentier elsewhere, but I'll award the points to Yitzhak
select a.image.value('.','nvarchar(max)') as image
from products r
cross apply r.xml.nodes('/product/images/*') a(image) where PLU='8019'
Microsoft SQL Server XML query: how can I get the data in ExtendedFields/Field/Identifier, ExtendedFields/Field/Identifier, IdentifierCode and OwnerID?
I am expecting to get values ID_US, US1 and John Smith.
Thanks
DECLARE #myDoc XML
DECLARE #ProdID varchar(30)
SET #myDoc = '<?xml version="1.0" encoding="UTF-8"?><MyFeed header="header value">
<f:TheFeed xmlns:f="urn:Thefeed-xsd">
<f:ConventionalValue>-100.681356</f:ConventionalValue><f:ReceiveXPercent>1.0</f:ReceiveXPercent><f:ReceiveXMonth>3</f:ReceiveXMonth>
<f:Fields><f:Field calcrt="SW1" name="Identifier">ID_US</f:Field><f:Field calcrt="SW5" name="IdentifierCode">US1</f:Field><f:Field calcrt="SW10" name="OwnerID">John Smith</f:Field>
</f:Fields>
</f:TheFeed>
</MyFeed>';
WITH XMLNAMESPACES(DEFAULT 'urn:Thefeed-xsd')
SELECT
OgrRol.value('(ConventionalValue/text())[1]','nvarchar(50)') AS ConventionalValue,
OgrRol.value('(ReceiveXPercent/text())[1]','nvarchar(50)') AS ReceiveXPercent,
OgrRol.value('(ReceiveXMonth/text())[1]','nvarchar(50)') AS ReceiveXMonth,
OgrRol.value('(ExtendedFields/#Identifier)[1]','nvarchar(50)') AS Identifier,
OgrRol.value('(ExtendedFields/#IdentifierCode)[1]','nvarchar(50)') AS IdentifierCode,
OgrRol.value('(ExtendedFields/#OwnerID)[1]','nvarchar(50)') AS OwnerID
FROM
#myDoc.nodes('/*:MyFeed/TheFeed') A(ogrRol)
Please try the following.
It is better not to use wildcard namespaces.
SQL
DECLARE #myDoc XML =
'<?xml version="1.0" encoding="UTF-8"?>
<MyFeed header="header value">
<f:TheFeed xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.fpml.org/2009/FpML-4-7"
xmlns:f="urn:Thefeed-xsd">
<f:ConventionalValue>-100.681356</f:ConventionalValue>
<f:ReceiveXPercent>1.0</f:ReceiveXPercent>
<f:ReceiveXMonth>3</f:ReceiveXMonth>
<f:ExtendedFields>
<f:Field calcrt="SW1" name="Identifier">ID_US</f:Field>
<f:Field calcrt="SW5" name="IdentifierCode">US1</f:Field>
<f:Field calcrt="SW10" name="OwnerID">John Smith</f:Field>
</f:ExtendedFields>
</f:TheFeed>
</MyFeed>';
WITH XMLNAMESPACES('urn:Thefeed-xsd' AS f)
SELECT c.value('(f:ConventionalValue/text())[1]','nvarchar(50)') AS ConventionalValue
,c.value('(f:ReceiveXPercent/text())[1]','nvarchar(50)') AS ReceiveXPercent
,c.value('(f:ReceiveXMonth/text())[1]','INT') AS ReceiveXMonth
,p.value('(f:Field[#calcrt="SW1"]/text())[1]','nvarchar(50)') AS Identifier
,p.value('(f:Field[#calcrt="SW5"]/text())[1]','nvarchar(50)') AS IdentifierCode
,p.value('(f:Field[#calcrt="SW10"]/text())[1]','nvarchar(50)') AS OwnerID
FROM #myDoc.nodes('/MyFeed/f:TheFeed') t1(c)
CROSS APPLY t1.c.nodes('f:ExtendedFields') AS t2(p);
Output
+-------------------+-----------------+---------------+------------+----------------+------------+
| ConventionalValue | ReceiveXPercent | ReceiveXMonth | Identifier | IdentifierCode | OwnerID |
+-------------------+-----------------+---------------+------------+----------------+------------+
| -100.681356 | 1.0 | 3 | ID_US | US1 | John Smith |
+-------------------+-----------------+---------------+------------+----------------+------------+
Can anyone help me to find out the SQL query for following scenario.
I have a search box, which I want to search multiple names separated by spaces.
for example : "David Jones" which gives me the result of David's details and Jones details.
select
emp.cid as empcid,
emp.name,
emp.employeeno,
info.employeeUniqueId,
info.agentId,
info.empBankCode,
info.accountNumber,
info.ibanAccNo
from tblemployee emp,
fk_tblUserEmployeeList f,
empinfo info
where
info.employee = emp.cid
and emp.cid = f.employeeid
and f.userId = 1
and
(
name like '%david%'
or emp.employeeno like '%david%'
or info.employeeUniqueId like '%david%'
or info.agentId like '%david%'
or info.empBankCode like '%david%'
or info.accountNumber like '%david%'
)
I want include Jones inside search box also, then how will the like condition changes>
This seems like a case for full-text search. After setting up full-text indices on your tblemployee, fk_tblUserEmployeeList, and empinfo tables, your query would look something like this:
SELECT
emp.cid AS empcid,
emp.name,
emp.employeeno,
info.employeeUniqueID,
info.agentID,
info.empBankCode,
info.accountNumber,
info.ibanAccNo
FROM dbo.tblemployee emp
INNER JOIN dbo.fk_tblUserEmployeeList f ON
f.employeeid = emp.cid
INNER JOIN dbo.empinfo info ON
info.employee = emp.cid
WHERE
f.userID = 1
AND
( FREETEXT(Emp.*, 'david jones')
OR FREETEXT(info.*, 'david jones')
)
gives you this data:
+--------+-------+------------+------------------+---------+-------------+---------------+-----------+
| empcid | name | employeeno | employeeUniqueID | agentID | empBankCode | accountNumber | ibanAccNo |
+--------+-------+------------+------------------+---------+-------------+---------------+-----------+
| 1 | David | NULL | david | david | david | david | david |
| 2 | Jones | NULL | jones | jones | jones | jones | jones |
+--------+-------+------------+------------------+---------+-------------+---------------+-----------+
Note that I changed your query to use the modern industry-standard join style.
Keep in mind that, to create a full-text index on a table, the table must have a single-column unique index. If one of your tables has a multi-column primary key, you'll have to add a column (see this question for more information).
A couple of notes about your naming conventions:
There's no need to preface table names with tbl (especially since you're not doing so consistently). There are loads of people telling you not to do this: See this answer as an example.
fk_tblUserEmployeeList is a bad table name: The prefixes fk and tbl don't add any information. What kind of information is stored in this table? I would suggest a more descriptive name (with no prefixes).
Now, if you don't want to go the route of using a full-text index, you can parse the input client-side before sending to SQL Server. You can split the search input on a space, and then construct the SQL accordingly.
declare #SearchString varchar(200)='David Jones', #Word varchar(100)
declare #Words table (Word varchar(100))
-- Parse the SearchString to extract all words
while len(#SearchString) > 0 begin
if charindex(' ', #SearchString)>0 begin
select #Word = rtrim(ltrim(substring(#SearchString,0,charindex(' ', #SearchString)))),
#SearchString = rtrim(ltrim(replace(#SearchString, #Word, '')))
end
else begin
select #Word = #SearchString,
#SearchString = ''
end
if #Word != ''
insert into #Words select #Word
end
-- Return Results
select t.*
from MyTable t
join #Words w on
' ' + t.MyColumn + ' ' like '%[^a-z]' + w.Word + '[^a-z]%'
Using SQLServer2008R2
I currently have XML tags with data inside the XML tags (not between them), such as:
<zooid="1"><animals key="all" zebras="22" dogs="0" birds="4" /><animals key="all" workers="yes" vacation="occasion" /> ... *(more)*</zooid>
<zooid="2"><animals key="house" zebras="0" dogs="1" birds="2" /><animals key="house" workers="no" vacation="no" /> ... *(more)*</zoodid>
If I query the XML or use the value function against it, it returns blank values because it tries to read between tags - where no value exists. I need it to read inside of the tags, parse out the values before the equal sign as columns and the values between the quotations as values inside those columns (granted, I could create a function that could do this, but this would be quite meticulous, and I'm curious if something like this already exists). What it should look like this in columns:
Key | Zebras | Dogs | Birds | Key | Workers | Vacation | ... *(more)*
... and this in rows of data:
all | 22 | 0 | 4 | all | yes | occasion | ... *(more)*
house | 0 | 1 | 2 | house | no | no | ... *(more)*
So the final output (just using the two XML rows from the beginning for now), would look like the below data in table form:
Key | Zebras | Dogs | Birds | Key | Workers | Vacation | ... *(more)*
================================================================
all | 22 | 0 | 4 | all | yes | occasion | ... *(more)*
house | 0 | 1 | 2 | house | no | no | ... *(more)*
Other than querying against XML, using the .query tool and even trying the .node tool (using CROSS APPLY see this thread), I haven't been able to generate this.
Try this one -
DECLARE #YourXML NVARCHAR(MAX)
SELECT #YourXML = '
<zooid="1">
<animals key="all" zebras="22" dogs="0" birds="4" />
<animals key="all" workers="yes" vacation="occasion" />
</zooid>
<zooid="2">
<animals key="house" zebras="0" dogs="1" birds="2" />
<animals key="house" workers="no" vacation="no" />
</zoodid>'
DECLARE #XML XML
SELECT #XML =
REPLACE(
REPLACE(#YourXML, 'zooid=', 'zooid id=')
, '</zoodid>'
, '</zooid>')
SELECT
d.[Key]
, Dogs = MAX(d.Dogs)
, Zebras = MAX(d.Zebras)
, Birds = MAX(d.Birds)
, Workers = MAX(d.Workers)
, Vacation = MAX(d.Vacation)
FROM (
SELECT
[Key] = t.p.value('./#key', 'NVARCHAR(50)')
, Zebras = t.p.value('./#zebras', 'INT')
, Dogs = t.p.value('./#dogs', 'INT')
, Birds = t.p.value('./#birds', 'INT')
, Workers = t.p.value('./#workers', 'NVARCHAR(20)')
, Vacation = t.p.value('./#vacation', 'NVARCHAR(20)')
FROM #XML.nodes('/zooid/animals') t(p)
) d
GROUP BY d.[Key]
Your xml appears invalid. How are you able to specify an element like this: ? Generally xml structure is <(elementName) (Attribute)="(Value)"/>. Unless I am mistaken if you are casting text to xml the way it is it will fail. Saying that I can show a working example for proper xml in a self extracting example that will run in SQL Managment Studio as is.
declare #text1 varchar(max) = '<zooid="1"><animals="all" zebras="22" dogs="0" birds="4" /><animals="all" workers="yes" vacation="occasion" /></zooid>'
, #text2 varchar(max) = '<a zooid="1"><b animals="all" zebras="22" dogs="0" birds="4" /><b animals="all" workers="yes" vacation="occasion" /></a>'
, #xml xml
;
begin try
set #xml = cast(#text1 as xml)
end try
begin catch
set #xml = '<ElementName Attribute="BadData Elements are not named" />'
end catch
select #xml
begin try
set #xml = cast(#text2 as xml)
end try
begin catch
set #xml = '<ElementName Attribute="BadData" />'
end catch
select
#xml.value('(/a/b/#animals)[1]', 'varchar(20)') as AnimalsValue
, #xml.value('(/a/b/#zebras)[1]', 'int') as ZebrasValue
, #xml.value('(/a/b/#dogs)[1]', 'int') as DogsValue
, #xml.value('(/a/b/#birds)[1]', 'int') as BirdsValue
, #xml.value('(/a/b/#workers)[1]', 'varchar(16)') as Workers
, #xml.value('(/a/b/#vacation)[1]', 'varchar(16)') as Vacation
The '.value' method is a syntax for querying xml in SQL. I am basically finding the elements(I did generics of a that contained b). Then once at the level I want '#animals' stands for 'attribute of name animals'. The [1] is a position since I can only return one thing at a time, so I chose the first position. Then it needs to a datatype to return. Text is varchar and numbers are ints.
XML query methods: http://msdn.microsoft.com/en-us/library/ms190798.aspx
How can I query multiple nodes in XML data with T-SQL and have the result output to a single comma separated string?
For example, I'd like to get a list of all the destination names in the following XML to look like "Germany, France, UK, Italy, Spain, Portugal"
<Holidays>
<Summer>
<Regions>
<Destinations>
<Destination Name="Germany" />
<Destination Name="France" />
<Destination Name="UK" />
<Destination Name="Italy" />
<Destination Name="Spain" />
<Destination Name="Portugal" />
</Destinations>
<Regions>
</Summer>
</Holidays>
I was trying something like:
Countries = [xmlstring].value('/Holidays/Summer/Regions/Destinations/#Name', 'varchar')
First, to get a list of records from a source XML table, you need to use the .nodes function (DEMO):
select Destination.value('data(#Name)', 'varchar(50)') as name
from [xmlstring].nodes('/Holidays/Summer/Regions/Destinations/Destination')
D(Destination)
Sample output:
| NAME |
-------------
| Germany |
| France |
| UK |
| Italy |
| Spain |
| Portugal |
From here, you want to concatenate the destination values into a comma-separated list. Unfortunately, this is not directly supported by T-SQL, so you'll have to use some sort of workaround. If you're working with a source table using multiple rows, the simplest method is the FOR XML PATH('') trick. In this query I use a source table called Data, and split out the XML into separate records, which I then CROSS APPLY with FOR XML PATH('') to generate comma-separated rows. Finally, the final , is stripped from the result to create the list (DEMO):
;with Destinations as (
select id, name
from Data
cross apply (
select Destination.value('data(#Name)', 'varchar(50)') as name
from [xmlstring].nodes('/Holidays/Summer/Regions/Destinations/Destination') D(Destination)
) Destinations(Name)
)
select id, substring(NameList, 1, len(namelist) - 1)
from Destinations as parent
cross apply (
select name + ','
from Destinations as child
where parent.id = child.id
for xml path ('')
) DestList(NameList)
group by id, NameList
Sample Output (Note that I've added another XML fragment to the test data to make a more complex example):
| ID | COLUMN_1 |
-----------------------------------------------
| 1 | Germany,France,UK,Italy,Spain,Portugal |
| 2 | USA,Australia,Brazil |