I have an ID table. Right now I just need to generate a XML file as the following format. Actually, it is a list of integers.
--Target format
<ListOfIntegers>
<Integer>150356</Integer>
<Integer>150365</Integer>
</ListOfIntegers>
I tried to use this and many other ways,
SELECT #tempXML = ( SELECT ID AS [Integer]
FROM #tempIDTable
FOR XML PATH('ListOfIntegers'), ELEMENTS)
But it will only generate a XML file like
--Current format
<ListOfIntegers>
<Integer>150356</Integer>
</ListOfIntegers>
<ListOfIntegers>
<Integer>150365</Integer>
</ListOfIntegers>
What should I do?
You were quite close:
CREATE TABLE #tempIDTable(ID INT);
INSERT INTO #tempIDTable VALUES(1),(2),(3);
DECLARE #tempXML XML;
SELECT #tempXML = ( SELECT ID AS [Integer]
FROM #tempIDTable
FOR XML PATH(''),ROOT('ListOfIntegers'));
SELECT #tempXML;
DROP TABLE #tempIDTable;
The result:
<ListOfIntegers>
<Integer>1</Integer>
<Integer>2</Integer>
<Integer>3</Integer>
</ListOfIntegers>
Related
I tryng to read xml file in sql server:
DECLARE #XMLToParse XML
-- Load the XML data in to a variable to work with.
-- This would typically be passed as a parameter to a stored proc
SET #XMLToParse = '<Response xmlns="http://tempuri.org/">
<AuthResult xmlns:a="http://schemas.datacontract.org/2004/07/Sistema.Soap.Contracts" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<a:Result>
<a:Id_Value>500</a:Id_Value>
</a:Result>
<a:Result>
<a:Id_Value>895</a:Id_Value>
</a:Result>
</AuthResult>
</Response>'
-- Declare temp table to parse data into
DECLARE #ParsingTable TABLE
(Id_Value INT)
-- Parse the XML in to the temp table declared above
INSERT
INTO #ParsingTable
(Id_Value)
SELECT xmlData.A.value('.', 'INT') AS Id_Value
FROM #XMLToParse.nodes('Response/AuthResult/Result') xmlData(A)
-- Insert into the actual table from the temp table
SELECT Id_Value
FROM #ParsingTable
Apparently the code is correct but I can not get the values, where can I be wrong?
Use WITH XMLNAMESPACES to declare the namespaces and use the respective prefix for nodes not in the default namespace.
...
-- Parse the XML in to the temp table declared above
;WITH XMLNAMESPACES (DEFAULT 'http://tempuri.org/',
'http://schemas.datacontract.org/2004/07/Sistema.Soap.Contracts' as a,
'http://www.w3.org/2001/XMLSchema-instance' as i
)
INSERT
INTO #ParsingTable
(Id_Value)
SELECT xmlData.A.value('.', 'INT') AS Id_Value
FROM #XMLToParse.nodes('Response/AuthResult/a:Result') xmlData(A)
...
I have a table with a xml column.
I require to search for sub string in that xml column for all its node and value. Search should be case insensitive
Structure of XML in each row is different
I used below query to do that,
select * from TableName Where Cast(xmlcolumn as varchar(max) ) like '%searchString%'
this works for short length xml rows, if row length goes huge it cant handle the situation. Only partial of the data was searched.
Suggest me some other ways to achieve.
If this is one time task then I would use exist XML method thus:
DECLARE #Table1 TABLE (
ID INT IDENTITY PRIMARY KEY,
CommentAsXML XML
)
INSERT #Table1 (CommentAsXML)
VALUES (N'<root><item /><item type="Reg">0001</item><item type="Inv">B007</item><item type="Cus">A0001</item><item type="Br">F0001</item></root>')
INSERT #Table1 (CommentAsXML)
VALUES (N'<root><item /><item type="Reg">0005</item><parent><child>B007</child></parent><item type="Br">F0005</item></root>')
INSERT #Table1 (CommentAsXML)
VALUES (N'<root><item /><item type="Reg">0005</item></root>')
-- Following query is searching for B007 within InnerText of all XML elements:
SELECT *
FROM #Table1 t
WHERE t.CommentAsXML.exist('//*[lower-case(text()[1]) eq "b007"]') = 1
Results:
ID CommentAsXML
-- ------------------------------------------------------------------------------------------------------------------------------
1 <root><item type="Reg">0001</item><item type="Inv">B007</item><item type="Cus">A0001</item><item type="Br">F0001</item></root>
2 <root><item type="Reg">0005</item><parent><child>B007</child></parent><item type="Br">F0005</item></root>
Also, if you want to search for some text in XML atrributes' values then following XQuery could be used:
SELECT *
FROM #Table1 t
WHERE t.CommentAsXML.exist('//#*[lower-case(.) eq "reg"]') = 1
Note: in both cases, string constants (ex. "reg") should be with lower cases.
I am trying to parse a simple XML file. As soon as I un comment the insert statement it gives me invalid column errors.
drop table #TEMP
drop table #TEMP_T
declare #XMl_DATA AS XML
set #XMl_DATA =
'<DocumentElement>
<Att_Table>
<L_ATTR_CD>GAS_FLOW_START_DATE</L_ATTR_CD>
<L_ATTR_DESC>GAS FLOW START DATE</L_ATTR_DESC>
<L_ATTR_VALUE>01/01/2012</L_ATTR_VALUE>
<R_ATTR_CD>EX_CTRCT_CO_ID</R_ATTR_CD>
<R_ATTR_DESC>EXCLUDE GID(S)</R_ATTR_DESC>
<R_ATTR_VALUE />
</Att_Table>
<Att_Table>
<L_ATTR_CD>GAS_FLOW_END_DATE</L_ATTR_CD>
<L_ATTR_DESC>GAS FLOW END DATE</L_ATTR_DESC>
<L_ATTR_VALUE>01/31/2012</L_ATTR_VALUE>
<R_ATTR_CD>EX_CTRCT_NBR</R_ATTR_CD>
<R_ATTR_DESC>EXCLUDE CONTRACT NUMBER(S)</R_ATTR_DESC>
<R_ATTR_VALUE />
</Att_Table>
<Att_Table>
<L_ATTR_CD>CTRCT_CO_ID</L_ATTR_CD>
<L_ATTR_DESC>GID(S)</L_ATTR_DESC>
<L_ATTR_VALUE />
<R_ATTR_CD>EX_RATE_CMPNT_CD</R_ATTR_CD>
<R_ATTR_DESC>EXCLUDE RATE COMPONENT CODE(S)</R_ATTR_DESC>
<R_ATTR_VALUE />
</Att_Table>
<Att_Table>
<L_ATTR_CD>CTRCT_NBR</L_ATTR_CD>
<L_ATTR_DESC>DART STYLE CONTRACT NUMBER(S)</L_ATTR_DESC>
<L_ATTR_VALUE />
<R_ATTR_CD>EX_PT_ID_NBR</R_ATTR_CD>
<R_ATTR_DESC>EXCLIDE POINT ID NUMBER(S)</R_ATTR_DESC>
<R_ATTR_VALUE />
</Att_Table>
</DocumentElement>'
Temp table:
CREATE TABLE #TEMP_T
(
ID INT IDENTITY(1,1),
ATT_CD VARCHAR(50),
ATT_CD_VALUE VARCHAR(1000)
)
SELECT
cast(Colx.query('data(L_ATTR_CD)') as varchar(max))as L_ATTR_CD,
cast(Colx.query('data(L_ATTR_VALUE)') as varchar(max))as L_ATTR_CD_VALUE,
cast(Colx.query('data(R_ATTR_CD)') as varchar(max)) as R_ATTR_CD,
cast(Colx.query('data(R_ATTR_VALUE)') as varchar(max))as R_ATTR_CD_VALUE
INTO #TEMP
FROM #XMl_DATA.nodes('DocumentElement/Att_Table') AS T(Colx)
--INSERT INTO #TEMP_T(ATT_CD,ATT_CD_VALUE)
--SELECT LTRIM(RTRIM(L_ATT_CD)),LTRIM(RTRIM(L_ATT_CD_VALUE))
--FROM #TEMP
--WHERE L_ATT_CD_VALUE <> 'NO_DATA'
--INSERT INTO #TEMP_T(ATT_CD,ATT_CD_VALUE)
--SELECT LTRIM(RTRIM(R_ATT_CD)),LTRIM(RTRIM(R_ATT_CD_VALUE))
--FROM #TEMP
--WHERE R_ATT_CD_VALUE <>'NO_DATA'
Output:
select * from #TEMP_T
select * from #TEMP
Sometimes you use things like L_ATTR and R_ATTR, and other times you use things like L_ATT and R_ATT (with no Rs). Pick one and stick to it.
The error message mentioning "invalid column" was trying to tell you this: the columns you try to select from #TEMP are "invalid" because you aren't using the same names as when you created #TEMP.
Why don't you just do something like this?
-- define your XML structure and create the #TEMP_T table
;WITH ParsedData AS
(
SELECT
Colx.value('(L_ATTR_CD)[1]', 'varchar(50)') as L_ATTR_CD,
Colx.value('(L_ATTR_VALUE)[1]', 'varchar(50)') as L_ATTR_CD_VALUE,
Colx.value('(R_ATTR_CD)[1]', 'varchar(50)') as R_ATTR_CD,
Colx.value('(R_ATTR_VALUE)[1]', 'varchar(50)') as R_ATTR_CD_VALUE
FROM
#XMl_DATA.nodes('DocumentElement/Att_Table') AS T(Colx)
)
INSERT INTO #temp_T(ATT_CD, ATT_CD_VALUE)
SELECT L_ATTR_CD, L_ATTR_CD_VALUE
FROM parseddata
UNION
SELECT R_ATTR_CD, R_ATTR_CD_VALUE
FROM parseddata
This just parses the XML (much simpler than your approach, too!) and then inserts both the (L_ATTR_CD, L_ATTR_CD_VALUE) as well as the (R_ATTR_CD, R_ATTR_CD_VALUE) pairs into the temp table in a single go.
If I have a SQL SERVER 2012 table containing an XML field type. The records it could contain are as follows.
I have simplified my problem to the following.
Record 1:
ID_FIELD='nn1'
XML_FIELD=
<KNOWN_NAME_1>
<UNKNOWN_NAME1>Some value</UNKNOWN_NAME1>
<UNKNOWN_NAME2>Some value</UNKNOWN_NAME2>
... Maybe more ...
</KNOWN_NAME_1>
Record 2:
ID_FIELD='nn2'
XML_FIELD=
<KNOWN_NAME_2>
<UNKNOWN_NAME1>Some value</UNKNOWN_NAME1>
<UNKNOWN_NAME2>Some value</UNKNOWN_NAME2>
... Maybe more unknown fields ...
</KNOWN_NAME_2>
I want to output non xml:
UNKNOWN_NAME1 | UNKNOWN_NAME2 | ETC
-----------------------------------
Some Value Some value
For a known root value (i.e. KNOWN_NAME_1)
I.e. If I new the node values (which I don't) I could
SELECT
XMLData.Node.value('UNKNOWN_NAME1[1]', 'varchar(100)') ,
XMLData.Node.value('UNKNOWN_NAME2[1], 'varchar(100)')
FROM FooTable
CROSS APPLY MyXmlField.nodes('//KNOWN_NAME_1') XMLData(Node)
-- WHERE SOME ID value = 'NN1' (all XML records have a separate id)
All is good however I want to do this for all the nodes (unknown quantity) without knowing the node names. The root will only contain nodes it wont get any deeper.
Is this possible in SQL?
I have looked at this but I doubt I can get enough rights to implement it.
http://architectshack.com/ClrXmlShredder.ashx
If you don't know the column names in the output you have to use dynamic SQL:
-- Source table
declare #FooTable table
(
ID_FIELD char(3),
XML_FIELD xml
)
-- Sample data
insert into #FooTable values
('nn1', '<KNOWN_NAME_1>
<UNKNOWN_NAME1>Some value1</UNKNOWN_NAME1>
<UNKNOWN_NAME2>Some value2</UNKNOWN_NAME2>
</KNOWN_NAME_1>')
-- ID to look for
declare #ID char(3) = 'nn1'
-- Element name to look for
declare #KnownName varchar(100) = 'KNOWN_NAME_1'
-- Variable to hold the XML to process
declare #XML xml
-- Get the XML
select #XML = XML_FIELD
from #FooTable
where ID_FIELD = #ID
-- Variable for dynamic SQL
declare #SQL nvarchar(max)
-- Build the query
select #SQL = 'select '+stuff(
(
select ',T.N.value('''+T.N.value('local-name(.)', 'sysname')+'[1]'', ''varchar(max)'') as '+T.N.value('local-name(.)', 'sysname')
from #XML.nodes('/*[local-name(.)=sql:variable("#KnownName")]/*') as T(N)
for xml path(''), type
).value('.', 'nvarchar(max)'), 1, 1, '')+
' from #XML.nodes(''/*[local-name(.)=sql:variable("#KnownName")]'') as T(N)'
-- Execute the query
exec sp_executesql #SQL,
N'#XML xml, #KnownName varchar(100)',
#XML = #XML,
#KnownName = #KnownName
Result:
UNKNOWN_NAME1 UNKNOWN_NAME2
--------------- ---------------
Some value1 Some value2
The dynamically generated query looks like this:
select T.N.value('UNKNOWN_NAME1[1]', 'varchar(max)') as UNKNOWN_NAME1,
T.N.value('UNKNOWN_NAME2[1]', 'varchar(max)') as UNKNOWN_NAME2
from #XML.nodes('/*[local-name(.)=sql:variable("#KnownName")]') as T(N)
SE-Data
I have table which contains columns like
SiteID (identity_Col)
SiteName
POrderID
Location
Address
Cluster
VenderName
I want to use xml string to insert/update/delete data in this table. Apart from this column, XML string contains one more column viz. RowInfo. This column will have values like "Unchanged","Update","New","Delete". Based on this values the rows in the table should be inserted,updated,deleted.
My XML string is as below:
<NewDataSet>
<DataTable>
<SiteID>2</SiteID>
<SiteName>NIZAMPURA</SiteName>
<POrderID>7</POrderID>
<Location>NIZAMPURA</Location>
<SiteAddress>Vadodara</SiteAddress>
<Cluster>002</Cluster>
<SubVendorName>Test Vender-1</SubVendorName>
<RowInfo>UNCHANGED</RowInfo>
</DataTable>
<DataTable>
<SiteID>16</SiteID>
<SiteName>Site-1</SiteName>
<POrderID>7</POrderID>
<Location>Alkapuri</Location>
<SiteAddress>test</SiteAddress>
<Cluster>Test Cluster</Cluster>
<SubVendorName>Test Vender12</SubVendorName>
<RowInfo>UNCHANGED</RowInfo>
</DataTable>
<DataTable>
<SiteID>17</SiteID>
<SiteName>Site-3</SiteName>
<POrderID>7</POrderID>
<Location>Alkapuri123</Location>
<SiteAddress>test123</SiteAddress>
<Cluster>Test Cluster123</Cluster>
<SubVendorName>Test Vender123</SubVendorName>
<RowInfo>DELETE</RowInfo>
</DataTable>
</NewDataSet>'
This is the code that I have written to insert data in table if RowInfo = "NEW"
IF len(ISNULL(#xmlString, '')) > 0
BEGIN
DECLARE #docHandle1 int = 0;
EXEC sp_xml_preparedocument #docHandle1 OUTPUT, #xmlString
INSERT INTO [SiteTRS] (
[SiteName],
[POrderID],
[Location],
[SiteAddress],
[Cluster],
[SubVendorName])
SELECT SiteName,POrderID,Location,SiteAddress,Cluster,SubVendorName
FROM OPENXML (#docHandle1, '/NewDataSet/DataTable')
WITH (SiteName varchar(50) './SiteName',
POrderID varchar(50) './PorderID',
Location varchar(50) './Location',
SiteAddress varchar(max) './SiteAddress',
Cluster varchar(50) './Cluster',
SubVendorName varchar(50) './SubVendorName',
RowInfo varchar(30) './RowInfo')
WHERE RowInfo='NEW'
But I don't know how to use XML to update/delete records in the table. Please guide
I am novice in the XML so dont have any idea. Please forgive me if I am making something childish.
I would strongly recommend not to use the old, legacy OPENXML stuff anymore - with XML support in SQL Server, it's much easier to use the built-in XPath/XQuery methods.
In your case, I would use a CTE (Common Table Expression) to break up the XML into an "inline" table of rows and columns:
DECLARE #input XML = '<NewDataSet>
<DataTable>
<SiteID>2</SiteID>
<SiteName>NIZAMPURA</SiteName>
<POrderID>7</POrderID>
<Location>NIZAMPURA</Location>
<SiteAddress>Vadodara</SiteAddress>
<Cluster>002</Cluster>
<SubVendorName>Vender-1</SubVendorName>
<RowInfo>UPDATE</RowInfo>
</DataTable>
<DataTable>
<SiteName>Site-1</SiteName>
<POrderID>7</POrderID>
<Location>Alkapuri</Location>
<SiteAddress>test</SiteAddress>
<Cluster>Cluster-1</Cluster>
<SubVendorName>Test Vender</SubVendorName>
<RowInfo>NEW</RowInfo>
</DataTable>
</NewDataSet>'
;WITH XMLData AS
(
SELECT
NDS.DT.value('(SiteID)[1]', 'int') AS 'SiteID',
NDS.DT.value('(SiteName)[1]', 'varchar(50)') AS 'SiteName',
NDS.DT.value('(POrderID)[1]', 'int') AS 'POrderID',
NDS.DT.value('(Location)[1]', 'varchar(100)') AS 'Location',
NDS.DT.value('(SiteAddress)[1]', 'varchar(100)') AS 'SiteAddress',
NDS.DT.value('(Cluster)[1]', 'varchar(100)') AS 'Cluster',
NDS.DT.value('(SubVendorName)[1]', 'varchar(100)') AS 'SubVendorName',
NDS.DT.value('(RowInfo)[1]', 'varchar(20)') AS 'RowInfo'
FROM
#input.nodes('/NewDataSet/DataTable') AS NDS(DT)
)
SELECT *
FROM XMLDATA
This gives you rows and columns which you can work with.
SiteID SiteName POrderID Location SiteAddress Cluster SubVendorName RowInfo
2 NIZAMPURA 7 NIZAMPURA Vadodara 002 Vender-1 UPDATE
NULL Site-1 7 Alkapuri test Cluster-1 Test Vender NEW
Now if you're on SQL Server 2008 or newer, you could combine this with the MERGE command to do your INSERT/UPDATE in a single statement, basically.
If you're on 2005, you will need to either store this information into a temporary table / table variable inside your stored proc, or you need to do the select multiple times; the CTE allows only one single command to follow it.
Update: with this CTE, you can then combine it with a MERGE:
;WITH XmlData AS
(
SELECT
NDS.DT.value('(SiteID)[1]', 'int') AS 'SiteID',
NDS.DT.value('(SiteName)[1]', 'varchar(50)') AS 'SiteName',
NDS.DT.value('(POrderID)[1]', 'int') AS 'POrderID',
NDS.DT.value('(Location)[1]', 'varchar(100)') AS 'Location',
NDS.DT.value('(SiteAddress)[1]', 'varchar(100)') AS 'SiteAddress',
NDS.DT.value('(Cluster)[1]', 'varchar(100)') AS 'Cluster',
NDS.DT.value('(SubVendorName)[1]', 'varchar(100)') AS 'SubVendorName',
NDS.DT.value('(RowInfo)[1]', 'varchar(20)') AS 'RowInfo'
FROM
#input.nodes('/NewDataSet/DataTable') AS NDS(DT)
)
MERGE INTO dbo.SiteTRS t
USING XmlData x ON t.SiteID = x.SiteID
WHEN MATCHED AND x.RowInfo = 'UPDATE'
THEN
UPDATE SET
t.SiteName = x.SiteName,
t.POrderID = x.POrderID,
t.Location = x.Location,
t.SiteAddress = x.SiteAddress,
t.Cluster = x.Cluster,
t.SubVendorName = x.SubVendorName
WHEN MATCHED AND x.RowInfo = 'DELETE'
THEN DELETE
WHEN NOT MATCHED AND x.RowInfo = 'NEW'
THEN
INSERT(SiteID, SiteName, POrderID, Location, SiteAddress, Cluster, SubVendorName)
VALUES(x.SiteID, x.SiteName, x.POrderID, x.Location, x.SiteAddress, x.Cluster, x.SubVendorName)
;
See some more resources:
SQL SERVER – 2008 – Introduction to Merge Statement – One Statement for INSERT, UPDATE, DELETE
Using SQL Server 2008's MERGE statement