I have the following sql stored procedure to bulk insert and parse an xml file and insert its data into several tables in a database.
The sql below works, however its inserting duplicate records into the #questions table and the #cards table.
Any help on this would be much appreciated. Thanks in advance.
Here is the XML file:
<?xml version="1.0" encoding="UTF-8"?>
<Users>
<User>
<UserInfo>
<Id>0001</Id>
<FirstName>John</FirstName>
<LastName>Doe</LastName>
<Email>Doejk#net.com</Email>
</UserInfo>
<Questions>
<Question>
<Id>1</Id>
<AnswerId>1</AnswerId>
</Question>
<Question>
<Id>2</Id>
<AnswerId>3</AnswerId>
</Question>
</Questions>
<Cards>
<Card>
<Id>1234</Id>
<Type>Digital</Type>
<Status>Active</Status>
</Card>
<Card>
<Id>1334</Id>
<Type>Physical</Type>
<Status>Not Active</Status>
</Card>
</Cards>
</User>
<User>
<UserInfo>
<Id>0002</Id>
<FirstName>Mary</FirstName>
<LastName>Doe</LastName>
<Email>Doem#net.com</Email>
</UserInfo>
<Questions>
<Question>
<Id>3</Id>
<AnswerId>6</AnswerId>
</Question>
<Question>
<Id>4</Id>
<AnswerId>7</AnswerId>
</Question>
</Questions>
<Cards>
<Card>
<Id>3333</Id>
<Type>Digital</Type>
<Status>Active</Status>
</Card>
<Card>
<Id>4444</Id>
<Type>Physical</Type>
<Status>Active</Status>
</Card>
</Cards>
</User>
</Users>
Here is SQL code
/*************************************************************************
-- CREATE TEMP TABLES --
**************************************************************************/
CREATE TABLE #XMLDATA
(RecordId int IDENTITY(1,1) NOT NULL,
XmlData xml NOT NULL)
CREATE TABLE #USERS
(UserID int null,
firstname varchar(50) null,
lastname varchar(50) null,
email varchar(50) null)
CREATE TABLE #CARDS
(CardId int null,
userid int null,
card_type varchar(50) null,
card_status varchar(50) null)
CREATE TABLE #QUESTIONS
(UserID int null,
Question_ID int null,
Answer_ID int null)
/*************************************************************************
-- LOAD THE WHOLE XML AS SINGLE BLOB --
**************************************************************************/
INSERT INTO #XMLDATA(XmlData)
SELECT *
FROM OPENROWSET(
BULK 'c:\users.xml', SINGLE_BLOB)
/*************************************************************************
-- INSERT USERS --
**************************************************************************/
INSERT INTO #USERS
(userid, firstname, lastname, email)
SELECT href.value('(Id/text())[1]', 'integer'),
href.value('(FirstName/text())[1]', 'varchar(50)'),
href.value('(LastName/text())[1]', 'varchar(50)'),
href.value('(Email/text())[1]', 'varchar(30)'),
FROM #XMLDATA CROSS APPLY
XmlData.nodes('Users') AS userinfo(href)
/*************************************************************************
-- INSERT QUESTIONS INFORMATION --
**************************************************************************/
INSERT INTO #QUESTIONS
(UserId, Question_ID, Answer_ID)
SELECT sref.value('(Id/text())[1]', 'integer'),
qref.value('(Id/text())[1]', 'integer'),
qref.value('(AnswerId/text())[1]', 'integer')
FROM #XMLDATA CROSS APPLY
XmlData.nodes('Users/Questions/Question') AS Ques(qref) CROSS APPLY
XmlData.nodes('Users') AS userinf(sref)
/*************************************************************************
-- INSERT CARD INFORMATION --
**************************************************************************/
INSERT INTO #CARDS
(userid, card_id, card_type,card_status)
SELECT sref.value('(Id/text())[1]', 'integer'),
cref.value('(Id/text())[1]', 'integer'),
cref.value('(Type/text())[1]', 'varchar(50)'),
cref.value('(Status/text())[1]', 'varchar(50)')
FROM #XMLDATA CROSS APPLY
XmlData.nodes('/Users/Cards/Card') AS cardlist(cref) CROSS APPLY
XmlData.nodes('/Users') AS userinf(sref)
I'm not sure what your CROSS JOIN is about.
Here is some shredding.
Tip: Comment out the INSERT portion and just do the SELECT portion until you get those tweaked correctly.
DECLARE #data XML;
SET #data =
N'
<Users>
<User>
<UserInfo>
<Id>0001</Id>
<FirstName>John</FirstName>
<LastName>Doe</LastName>
<Email>Doejk#net.com</Email>
</UserInfo>
<Questions>
<Question>
<Id>1</Id>
<AnswerId>1</AnswerId>
</Question>
<Question>
<Id>2</Id>
<AnswerId>3</AnswerId>
</Question>
</Questions>
<Cards>
<Card>
<Id>1234</Id>
<Type>Digital</Type>
<Status>Active</Status>
</Card>
<Card>
<Id>1334</Id>
<Type>Physical</Type>
<Status>Not Active</Status>
</Card>
</Cards>
</User>
<User>
<UserInfo>
<Id>0002</Id>
<FirstName>Mary</FirstName>
<LastName>Doe</LastName>
<Email>Doem#net.com</Email>
</UserInfo>
<Questions>
<Question>
<Id>3</Id>
<AnswerId>6</AnswerId>
</Question>
<Question>
<Id>4</Id>
<AnswerId>7</AnswerId>
</Question>
</Questions>
<Cards>
<Card>
<Id>3333</Id>
<Type>Digital</Type>
<Status>Active</Status>
</Card>
<Card>
<Id>4444</Id>
<Type>Physical</Type>
<Status>Active</Status>
</Card>
</Cards>
</User>
</Users>';
SELECT T.myEntity.value('(Id)[1]', 'VARCHAR(20)')
, T.myEntity.value('(FirstName)[1]', 'VARCHAR(20)')
, T.myEntity.value('(LastName)[1]', 'VARCHAR(20)')
, T.myEntity.value('(Email)[1]', 'VARCHAR(20)')
FROM #data.nodes('Users/User/UserInfo') AS T(myEntity);
SELECT
T.myEntity.value('(../../UserInfo/Id)[1]', 'VARCHAR(20)')
, T.myEntity.value('(Id)[1]', 'INT')
, T.myEntity.value('(AnswerId)[1]', 'INT')
FROM #data.nodes('Users/User/Questions/Question') AS T(myEntity);
SELECT
T.myEntity.value('(../../UserInfo/Id)[1]', 'VARCHAR(20)')
, T.myEntity.value('(Id)[1]', 'INT')
, T.myEntity.value('(Type)[1]', 'VARCHAR(20)')
, T.myEntity.value('(Status)[1]', 'VARCHAR(20)')
FROM #data.nodes('Users/User/Cards/Card') AS T(myEntity);
CREATE TABLE #XMLDATA
(RecordId int IDENTITY(1,1) NOT NULL,
XmlData xml NOT NULL)
CREATE TABLE #USERS
(UserID int null,
firstname varchar(50) null,
lastname varchar(50) null,
email varchar(50) null)
Related
I'm attempting to update a customer table using an XML file, but it's not pulling the values from the XML into the variables to pass into the table. The error I get says "Cannot insert the value NULL into column 'EmailAddress'" even though there is clearly a value for EmailAddress. I feel like I'm missing something very simple, but can't figure it out. Any thoughts?
USE MyGuitarShop
DECLARE #CustomerUpdate XML
SET #CustomerUpdate =
'<NewCustomers>
<Customer EmailAddress="izzychan#yahoo.com" Password="" FirstName="Isabella" LastName="Chan" />
<Customer EmailAddress="johnprine#gmail.com" Password="" FirstName="John" LastName="Prine" />
<Customer EmailAddress="kathykitchen#sbcglobal.net" Password="" FirstName="Kathy" LastName="Kitchen" />
</NewCustomers>';
INSERT Customers (EmailAddress, Password, FirstName, LastName)
VALUES
(
#CustomerUpdate.value('(/NewCustomers/Customer/EmailAddress)[1]', 'varchar(255)'),
#CustomerUpdate.value('(/NewCustomers/Customer/Password)[1]', 'varchar(60)'),
#CustomerUpdate.value('(/NewCustomers/Customer/FirstName)[1]', 'varchar(60)'),
#CustomerUpdate.value('(/NewCustomers/Customer/LastName)[1]', 'varchar(60)')
);
SELECT * FROM Customers
I feel like I'm missing something very simple ...
Yeah, you're right :-D, You are missing the # to read the attribute-value:
DECLARE #CustomerUpdate XML
SET #CustomerUpdate =
'<NewCustomers>
<Customer EmailAddress="izzychan#yahoo.com" Password="" FirstName="Isabella" LastName="Chan" />
<Customer EmailAddress="johnprine#gmail.com" Password="" FirstName="John" LastName="Prine" />
<Customer EmailAddress="kathykitchen#sbcglobal.net" Password="" FirstName="Kathy" LastName="Kitchen" />
</NewCustomers>';
SELECT
#CustomerUpdate.value('(/NewCustomers/Customer/#EmailAddress)[1]', 'varchar(255)'),
#CustomerUpdate.value('(/NewCustomers/Customer/#Password)[1]', 'varchar(60)'),
#CustomerUpdate.value('(/NewCustomers/Customer/#FirstName)[1]', 'varchar(60)'),
#CustomerUpdate.value('(/NewCustomers/Customer/#LastName)[1]', 'varchar(60)')
UPDATE: Insert all <Customer> in one go
Try this:
DECLARE #Customers TABLE(EMailAddress VARCHAR(100),[Password] VARCHAR(100),FirstName VARCHAR(100),LastName VARCHAR(100));
DECLARE #CustomerUpdate XML
SET #CustomerUpdate =
'<NewCustomers>
<Customer EmailAddress="izzychan#yahoo.com" Password="" FirstName="Isabella" LastName="Chan" />
<Customer EmailAddress="johnprine#gmail.com" Password="" FirstName="John" LastName="Prine" />
<Customer EmailAddress="kathykitchen#sbcglobal.net" Password="" FirstName="Kathy" LastName="Kitchen" />
</NewCustomers>';
INSERT INTO #Customers (EmailAddress, Password, FirstName, LastName)
SELECT c.value('#EmailAddress', 'varchar(255)')
,c.value('#Password', 'varchar(60)')
,c.value('#FirstName', 'varchar(60)')
,c.value('#LastName', 'varchar(60)')
FROM #CustomerUpdate.nodes(N'/NewCustomers/Customer') AS A(c)
SELECT * FROM #Customers
This code works perfectly now.
USE MyGuitarShop
DECLARE #CustomerUpdate XML
SET #CustomerUpdate =
'<NewCustomers>
<Customer EmailAddress="izzychan#yahoo.com" Password="" FirstName="Isabella" LastName="Chan" />
<Customer EmailAddress="johnprine#gmail.com" Password="" FirstName="John" LastName="Prine" />
<Customer EmailAddress="kathykitchen#sbcglobal.net" Password="" FirstName="Kathy" LastName="Kitchen" />
</NewCustomers>';
INSERT Customers (EmailAddress, Password, FirstName, LastName)
VALUES
(
#CustomerUpdate.value('(/NewCustomers/Customer/#EmailAddress)[1]', 'varchar(255)'),
#CustomerUpdate.value('(/NewCustomers/Customer/#Password)[1]', 'varchar(60)'),
#CustomerUpdate.value('(/NewCustomers/Customer/#FirstName)[1]', 'varchar(60)'),
#CustomerUpdate.value('(/NewCustomers/Customer/#LastName)[1]', 'varchar(60)')
);
INSERT Customers (EmailAddress, Password, FirstName, LastName)
VALUES
(
#CustomerUpdate.value('(/NewCustomers/Customer/#EmailAddress)[2]', 'varchar(255)'),
#CustomerUpdate.value('(/NewCustomers/Customer/#Password)[2]', 'varchar(60)'),
#CustomerUpdate.value('(/NewCustomers/Customer/#FirstName)[2]', 'varchar(60)'),
#CustomerUpdate.value('(/NewCustomers/Customer/#LastName)[2]', 'varchar(60)')
);
INSERT Customers (EmailAddress, Password, FirstName, LastName)
VALUES
(
#CustomerUpdate.value('(/NewCustomers/Customer/#EmailAddress)[3]', 'varchar(255)'),
#CustomerUpdate.value('(/NewCustomers/Customer/#Password)[3]', 'varchar(60)'),
#CustomerUpdate.value('(/NewCustomers/Customer/#FirstName)[3]', 'varchar(60)'),
#CustomerUpdate.value('(/NewCustomers/Customer/#LastName)[3]', 'varchar(60)')
);
SELECT * FROM Customers
I am trying to group some elements together under one node. This is my current SQL;
declare #xml xml
set #xml = (
select (
select
'DERIVED' '#type',
m.NuixDerivedFieldName '#name', (
SELECT
NuixFieldType as 'metadata/#type',
NuixFieldName as 'metadata/#name'
from eddsdbo.MetadataMapping m1
where m1.NuixDerivedFieldName = m.NuixDerivedFieldName
for xml path ('first-non-blank'), type
)
from (select distinct NuixDerivedFieldName from eddsdbo.MetadataMapping) m
for xml path ('metadata'))
)
;WITH XMLNAMESPACES(DEFAULT 'http://nuix.com/fbi/metadata-profile')
select #xml for XML PATH ('metadata-list'), ROOT ('metadata-profile')
Which gives me the following output;
<metadata-profile xmlns="http://nuix.com/fbi/metadata-profile">
<metadata-list>
<metadata type="DERIVED" name="Barcode" xmlns="">
<first-non-blank>
<metadata type="CUSTOM" name="Barcode" />
</first-non-blank>
<first-non-blank>
<metadata type="EVIDENCE" name="Barcode" />
</first-non-blank>
</metadata>
I want to group together elements together which have the same 'name' attribute of the metadata element under the <first-non-blank> element.
The desired output should be;
<metadata-profile xmlns="http://nuix.com/fbi/metadata-profile">
<metadata-list>
<metadata type="DERIVED" name="Barcode" xmlns="">
<first-non-blank>
<metadata type="CUSTOM" name="Barcode" />
<metadata type="EVIDENCE" name="Barcode" />
</first-non-blank>
</metadata>
...
My database looks something like this;
NuixFieldName NuixFieldType NuixDerivedFieldName
------------------------------ ------------------------------ ------------------------------
_EmailEntryID PROPERTY EmailEntryID
Audited Audited Audited
Author PROPERTY Author
Barcode CUSTOM Barcode
Barcode EVIDENCE Barcode
I would also like to remove the xlmns namespace identifier from the metadata elements.
Thanks in advance!
You could try this
DECLARE #SampleData AS TABLE
(
NuixFieldName varchar(20),
NuixFieldType varchar(20),
NuixDerivedFieldName varchar(20)
)
INSERT INTO #SampleData
VALUES
('_EmailEntryID','PROPERTY','EmailEntryID'),
('Audited', 'Audited ','Audited'),
('Author ', 'PROPERTY','Author '),
('Barcode', 'CUSTOM ','Barcode'),
('Barcode', 'EVIDENCE','Barcode')
DECLARE #xml XML
SET #xml = (
SELECT
-- sd.NuixDerivedFieldName AS [#name],
'DERIVED' AS [#type],
sd.NuixDerivedFieldName AS [#name],
(
SELECT
sd2.NuixFieldType as '#type',
sd2.NuixFieldName as '#name'
FROM #SampleData sd2 WHERE sd2.NuixDerivedFieldName = sd.NuixDerivedFieldName
FOR XML PATH ('metadata'),ROOT('first-non-blank'), TYPE
)
FROM (select DISTINCT sd.NuixDerivedFieldName from #SampleData sd ) sd
FOR XML PATH('metadata'), ROOT('metadata-list'),TYPE
)
;WITH XMLNAMESPACES(DEFAULT 'http://nuix.com/fbi/metadata-profile')
SELECT #xml FOR XML PATH (''),ROOT('metadata-profile')
return:
<metadata-profile xmlns="http://nuix.com/fbi/metadata-profile">
<metadata-list>
<metadata type="DERIVED" name="Audited">
<first-non-blank>
<metadata type="Audited " name="Audited" />
</first-non-blank>
</metadata>
<metadata type="DERIVED" name="Author ">
<first-non-blank>
<metadata type="PROPERTY" name="Author " />
</first-non-blank>
</metadata>
<metadata type="DERIVED" name="Barcode">
<first-non-blank>
<metadata type="CUSTOM " name="Barcode" />
<metadata type="EVIDENCE" name="Barcode" />
</first-non-blank>
</metadata>
<metadata type="DERIVED" name="EmailEntryID">
<first-non-blank>
<metadata type="PROPERTY" name="_EmailEntryID" />
</first-non-blank>
</metadata>
</metadata-list>
</metadata-profile>
I have some xml like:
<MyDetails>
<detail key="key1" value="value1" />
<detail key="key2" value="value2" />
<detail key="key3" value="value3" />
<detail key="key4" value="value4" />
</MyDetails>
And I want to be able to parse it in a table format of two columns Key, and Value. How can I create a SQL function to achieve this by specifying a Node path i.e. in this case '/MyDetails/detail' and KeyAttributeName and ValueAttributeName. I created the following function but it gives me the error:
ALTER FUNCTION [dbo].[GetXmlTable] (
#XmlSource XML,
#HierarchyPath NVARCHAR(50) = '',
#SpecificKey NVARCHAR(255) = NULL,
#KeyAttributeName NVARCHAR(50) = 'key',
#ValueAttributeName NVARCHAR(50) = 'value'
)
RETURNS #Table TABLE (
[Key] NVARCHAR(255),
[Value] NVARCHAR(500)
)
AS
BEGIN
DECLARE #KeyAttribute NVARCHAR (50) = '#' + #KeyAttributeName
DECLARE #ValueAttribute NVARCHAR (50) = '#' + #ValueAttributeName
DECLARE #Path NVARCHAR (50) = '/' + #HierarchyPath
INSERT INTO #Table
SELECT XmlElement.Attribute.value(#KeyAttribute, 'nvarchar(255)') AS [Key]
,XmlElement.Attribute.value(#ValueAttribute, 'nvarchar(500)') AS [Value]
FROM #XmlSource.nodes(#Path) AS XmlElement(Attribute)
WHERE #SpecificKey IS NULL OR XmlElement.Attribute.value(#KeyAttribute, 'nvarchar(255)') = #SpecificKey
RETURN
END
GO
Error:
Msg 8172, Level 16, State 1, Procedure GetXmlTable, Line 12 The
argument 1 of the XML data type method "nodes" must be a string
literal.
Looking to call the function like this:
select * from dbo.GetXmlTable(CAST('<MyDetails>
<detail key="key1" value="value1" />
<detail key="key2" value="value2" />
<detail key="key3" value="value3" />
<detail key="key4" value="value4" />
</MyDetails>' as XML), 'MyDetails/detail', default, default, default)
UPDATE---------------
I tried using sql variable syntax but the table returned is blank. Can you please point out what I might be doing wrong:
DECLARE #KeyAttr VARCHAR(50) = N'#' + #KeyAttributeName
DECLARE #ValueAttr VARCHAR(50) = N'#' + #ValueAttributeName
DECLARE #Path VARCHAR(100) = '/' + #HierarchyPath
INSERT INTO #Table
SELECT XmlElement.Attribute.value('(*[local-name() = sql:variable("#KeyAttr")])[1]', 'nvarchar(255)') AS [Key]
,XmlElement.Attribute.value('(*[local-name() = sql:variable("#ValueAttr")][1])', 'nvarchar(500)') AS [Value]
FROM #XmlSource.nodes('(*[local-name() = sql:variable("#Path")])') AS XmlElement(Attribute)
WHERE #SpecificKey IS NULL OR XmlElement.Attribute.value('(*[local-name() = sql:variable("#KeyAttr")])[1]', 'nvarchar(255)') = #SpecificKey
This query will shred your XML into a simple table;
declare #xml xml = '<MyDetails>
<detail key="key1" value="value1" />
<detail key="key2" value="value2" />
<detail key="key3" value="value3" />
<detail key="key4" value="value4" />
</MyDetails>'
select
t.c.value('#key', 'varchar(100)') as [key],
t.c.value('#value', 'varchar(100)') as value
from
#xml.nodes('/MyDetails/detail') as t(c)
The error "The argument 1 of the XML data type method "nodes" must be a string literal." means exactly what it says - you can't pass a variable as the argument to the nodes() method. You can however reference variables in the XQuery passed to Nodes() - see sql:variable() for more info.
I have a huge XML, with over 150 element and attributes. I need to populate only a handful of them ( 5 or 6) elements with data from a SQL server 2008 tables. This created xml need to be passed to a webservice ( to ESB) and this has to happen on a daily schedule.
I think, it does not make sense to use XML Path here to create the XML and use SSIS. Can anyone suggest an approach?
This is the sample XML. I need just the names, address and a few ids populated
<?xml version="1.0" encoding="UTF-8"?>
<Customer xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="Customer.xsd">
<CustomerData>
<StoreID></StoreID>
<FirstName></FirstName>
<LastName></LastName>
<Gender></Gender>
<BirthMonth></BirthMonth>
<BirthYear></BirthYear>
<BirthDay></BirthDay>
<IsEmployee></IsEmployee>
<customerID></customerID>
<EmailAddress></EmailAddress>
<PhoneNumber></PhoneNumber>
<EmailSignUp></EmailSignUp>
<CatalogSignup></CatalogSignup>
<Addresses>
<BillingAddress>
<Address1></Address1>
<Address2></Address2>
<Address3></Address3>
<City></City>
<State></State>
<ZipCode></ZipCode>
<Fax1></Fax1>
</BillingAddress>
<CatalogSignupAddress>
<Address1></Address1>
<Address2></Address2>
<Address3></Address3>
<City></City>
<State></State>
<ZipCode></ZipCode>
<Fax1></Fax1>
</CatalogSignupAddress>
<StoredAddresses>
<StoredAddress>
<Address1></Address1>
<Address2></Address2>
<Address3></Address3>
<City></City>
<State></State>
<ZipCode></ZipCode>
<Fax1></Fax1>
</StoredAddress>
<StoredAddress>
<Address1></Address1>
<Address2></Address2>
<Address3></Address3>
<City></City>
<State></State>
<ZipCode></ZipCode>
<Fax1></Fax1>
</StoredAddress>
</StoredAddresses>
</Addresses>
<Hobbies_Enjoys>
<Hobby></Hobby>
<Enjoy></Enjoy>
</Hobbies_Enjoys>
<FavoriteFossilProducts>
<ProductType></ProductType>
<ProductType></ProductType>
</FavoriteFossilProducts>
<AgeRange></AgeRange>
<PreferredEmailFormat></PreferredEmailFormat>
<SavedCreditCards>
<CreditCard>
<AcctNum></AcctNum>
<ExpiryDate></ExpiryDate>
</CreditCard>
<CreditCard>
<AcctNum></AcctNum>
<ExpiryDate></ExpiryDate>
</CreditCard>
</SavedCreditCards>
<PurchasedProductList>
<SKU></SKU>
<SKU></SKU>
</PurchasedProductList>
<OrderHistory>
<Orders>
<Order>
<Number></Number>
<TotalAmount></TotalAmount>
<Promotion></Promotion>
<TimePlaced></TimePlaced>
</Order>
<Order>
<Number></Number>
<TotalAmount></TotalAmount>
<Promotion></Promotion>
<TimePlaced></TimePlaced>
</Order>
</Orders>
</OrderHistory>
<WishLists>
<WishList>
<Name></Name>
<Description></Description>
<DateCreated></DateCreated>
<LastUpdate></LastUpdate>
<IsDefault></IsDefault>
<Items>
<Item>
<Quantity></Quantity>
<PartNumber></PartNumber>
<DateCreated></DateCreated>
<LastUpdate></LastUpdate>
</Item>
<Item>
<Quantity></Quantity>
<PartNumber></PartNumber>
<DateCreated></DateCreated>
<LastUpdate></LastUpdate>
</Item>
</Items>
</WishList>
<WishList>
<Name></Name>
<Description></Description>
<DateCreated></DateCreated>
<LastUpdate></LastUpdate>
<IsDefault></IsDefault>
<Items>
<Item>
<Quantity></Quantity>
<PartNumber></PartNumber>
<DateCreated></DateCreated>
<LastUpdate></LastUpdate>
</Item>
<Item>
<Quantity></Quantity>
<PartNumber></PartNumber>
<DateCreated></DateCreated>
<LastUpdate></LastUpdate>
</Item>
</Items>
</WishList>
</WishLists>
</CustomerData>
<CustomerData>
</CustomerData>
</Customer>
One approach is to take an empty version of your XML document and assign it to an NVARCHAR(MAX) variable. For each node or parameter you wish to populate, put a "token" and use the replace function to populate the value. For example:
DECLARE #xml NVARCHAR(MAX)
SET #xml = N'<Company name="~company_name~">
<Department name="~dept_name~">
<Employee name="~employee_name~" title="~employee_title~" />
</Department>
</Company>'
SET #xml = REPLACE(#xml,N'~company_name~','Microsoft')
SET #xml = REPLACE(#xml,N'~dept_name~','Executive')
SET #xml = REPLACE(#xml,N'~employee_name~','Satya Nadella')
SET #xml = REPLACE(#xml,N'~employee_title~','CEO')
SELECT CAST(#xml AS XML)
Here's a more traditional approach. You'll need an arbitrary value in the cells you wish to update:
DECLARE #example_data TABLE
(FirstName VARCHAR(255) NOT NULL,
LastName VARCHAR(255) NOT NULL,
Gender CHAR(1) NOT NULL,
City VARCHAR(255) NOT NULL,
[State] CHAR(2) NOT NULL)
INSERT INTO #example_data
( FirstName , LastName , Gender , City , [State])
VALUES ( 'Satya' , -- FirstName - varchar(255)
'Nadella' , -- LastName - varchar(255)
'M' , -- Gender - char(1)
'Redmond' , -- City - varchar(255)
'WA' -- State - char(2)
)
INSERT INTO #example_data
( FirstName , LastName , Gender , City , [State])
VALUES ( 'Larry' , -- FirstName - varchar(255)
'Ellison' , -- LastName - varchar(255)
'M' , -- Gender - char(1)
'Woodside' , -- City - varchar(255)
'CA' -- State - char(2)
)
DECLARE
#customer_xml XML,
#xml XML,
#temp NVARCHAR(255),
#FirstName VARCHAR(255),
#LastName VARCHAR(255),
#Gender CHAR(1),
#City VARCHAR(255),
#State CHAR(2)
SET #customer_xml = '<?xml version="1.0" encoding="UTF-8"?>
<Customer xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="Customer.xsd">
<CustomerData>
<StoreID></StoreID>
<FirstName>a</FirstName>
<LastName>b</LastName>
<Gender>c</Gender>
<BirthMonth></BirthMonth>
<BirthYear></BirthYear>
<BirthDay></BirthDay>
<IsEmployee></IsEmployee>
<customerID></customerID>
<EmailAddress></EmailAddress>
<PhoneNumber></PhoneNumber>
<EmailSignUp></EmailSignUp>
<CatalogSignup></CatalogSignup>
<Addresses>
<BillingAddress>
<Address1></Address1>
<Address2></Address2>
<Address3></Address3>
<City>d</City>
<State>e</State>
<ZipCode></ZipCode>
<Fax1></Fax1>
</BillingAddress>
<CatalogSignupAddress>
<Address1></Address1>
<Address2></Address2>
<Address3></Address3>
<City></City>
<State></State>
<ZipCode></ZipCode>
<Fax1></Fax1>
</CatalogSignupAddress>
<StoredAddresses>
<StoredAddress>
<Address1></Address1>
<Address2></Address2>
<Address3></Address3>
<City></City>
<State></State>
<ZipCode></ZipCode>
<Fax1></Fax1>
</StoredAddress>
<StoredAddress>
<Address1></Address1>
<Address2></Address2>
<Address3></Address3>
<City></City>
<State></State>
<ZipCode></ZipCode>
<Fax1></Fax1>
</StoredAddress>
</StoredAddresses>
</Addresses>
<Hobbies_Enjoys>
<Hobby></Hobby>
<Enjoy></Enjoy>
</Hobbies_Enjoys>
<FavoriteFossilProducts>
<ProductType></ProductType>
<ProductType></ProductType>
</FavoriteFossilProducts>
<AgeRange></AgeRange>
<PreferredEmailFormat></PreferredEmailFormat>
<SavedCreditCards>
<CreditCard>
<AcctNum></AcctNum>
<ExpiryDate></ExpiryDate>
</CreditCard>
<CreditCard>
<AcctNum></AcctNum>
<ExpiryDate></ExpiryDate>
</CreditCard>
</SavedCreditCards>
<PurchasedProductList>
<SKU></SKU>
<SKU></SKU>
</PurchasedProductList>
<OrderHistory>
<Orders>
<Order>
<Number></Number>
<TotalAmount></TotalAmount>
<Promotion></Promotion>
<TimePlaced></TimePlaced>
</Order>
<Order>
<Number></Number>
<TotalAmount></TotalAmount>
<Promotion></Promotion>
<TimePlaced></TimePlaced>
</Order>
</Orders>
</OrderHistory>
<WishLists>
<WishList>
<Name></Name>
<Description></Description>
<DateCreated></DateCreated>
<LastUpdate></LastUpdate>
<IsDefault></IsDefault>
<Items>
<Item>
<Quantity></Quantity>
<PartNumber></PartNumber>
<DateCreated></DateCreated>
<LastUpdate></LastUpdate>
</Item>
<Item>
<Quantity></Quantity>
<PartNumber></PartNumber>
<DateCreated></DateCreated>
<LastUpdate></LastUpdate>
</Item>
</Items>
</WishList>
<WishList>
<Name></Name>
<Description></Description>
<DateCreated></DateCreated>
<LastUpdate></LastUpdate>
<IsDefault></IsDefault>
<Items>
<Item>
<Quantity></Quantity>
<PartNumber></PartNumber>
<DateCreated></DateCreated>
<LastUpdate></LastUpdate>
</Item>
<Item>
<Quantity></Quantity>
<PartNumber></PartNumber>
<DateCreated></DateCreated>
<LastUpdate></LastUpdate>
</Item>
</Items>
</WishList>
</WishLists>
</CustomerData>
</Customer>'
DECLARE xml_cursor CURSOR FOR
SELECT FirstName , LastName , Gender , City , [State]
FROM #example_data
OPEN xml_cursor
FETCH NEXT FROM xml_cursor into #FirstName, #LastName, #Gender, #City, #State
WHILE ##fetch_status = 0
BEGIN
SET #xml = #customer_xml
SET #xml.modify('
replace value of (/Customer/CustomerData/FirstName[1]/text())[1]
with sql:variable("#FirstName")
')
SET #xml.modify('
replace value of (/Customer/CustomerData/LastName[1]/text())[1]
with sql:variable("#LastName")
')
SET #xml.modify('
replace value of (/Customer/CustomerData/Gender[1]/text())[1]
with sql:variable("#Gender")
')
SET #xml.modify('
replace value of (/Customer/CustomerData/Addresses/BillingAddress/City[1]/text())[1]
with sql:variable("#City")
')
SET #xml.modify('
replace value of (/Customer/CustomerData/Addresses/BillingAddress/State[1]/text())[1]
with sql:variable("#State")
')
select #xml
FETCH NEXT FROM xml_cursor into #FirstName, #LastName, #Gender, #City, #State
END
This approach does not require a value in the nodes to be updated. It simply inserts a new node, then deletes the old node:
DECLARE #example_data TABLE
(FirstName VARCHAR(255) NOT NULL,
LastName VARCHAR(255) NOT NULL,
Gender CHAR(1) NOT NULL,
City VARCHAR(255) NOT NULL,
[State] CHAR(2) NOT NULL)
INSERT INTO #example_data
( FirstName , LastName , Gender , City , [State])
VALUES ( 'Satya' , -- FirstName - varchar(255)
'Nadella' , -- LastName - varchar(255)
'M' , -- Gender - char(1)
'Redmond' , -- City - varchar(255)
'WA' -- State - char(2)
)
INSERT INTO #example_data
( FirstName , LastName , Gender , City , [State])
VALUES ( 'Larry' , -- FirstName - varchar(255)
'Ellison' , -- LastName - varchar(255)
'M' , -- Gender - char(1)
'Woodside' , -- City - varchar(255)
'CA' -- State - char(2)
)
DECLARE
#customer_xml XML,
#xml XML,
#temp NVARCHAR(255),
#FirstName VARCHAR(255),
#LastName VARCHAR(255),
#Gender CHAR(1),
#City VARCHAR(255),
#State CHAR(2)
SET #customer_xml = '<?xml version="1.0" encoding="UTF-8"?>
<Customer xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="Customer.xsd">
<CustomerData>
<StoreID></StoreID>
<FirstName></FirstName>
<LastName></LastName>
<Gender></Gender>
<BirthMonth></BirthMonth>
<BirthYear></BirthYear>
<BirthDay></BirthDay>
<IsEmployee></IsEmployee>
<customerID></customerID>
<EmailAddress></EmailAddress>
<PhoneNumber></PhoneNumber>
<EmailSignUp></EmailSignUp>
<CatalogSignup></CatalogSignup>
<Addresses>
<BillingAddress>
<Address1></Address1>
<Address2></Address2>
<Address3></Address3>
<City></City>
<State></State>
<ZipCode></ZipCode>
<Fax1></Fax1>
</BillingAddress>
<CatalogSignupAddress>
<Address1></Address1>
<Address2></Address2>
<Address3></Address3>
<City></City>
<State></State>
<ZipCode></ZipCode>
<Fax1></Fax1>
</CatalogSignupAddress>
<StoredAddresses>
<StoredAddress>
<Address1></Address1>
<Address2></Address2>
<Address3></Address3>
<City></City>
<State></State>
<ZipCode></ZipCode>
<Fax1></Fax1>
</StoredAddress>
<StoredAddress>
<Address1></Address1>
<Address2></Address2>
<Address3></Address3>
<City></City>
<State></State>
<ZipCode></ZipCode>
<Fax1></Fax1>
</StoredAddress>
</StoredAddresses>
</Addresses>
<Hobbies_Enjoys>
<Hobby></Hobby>
<Enjoy></Enjoy>
</Hobbies_Enjoys>
<FavoriteFossilProducts>
<ProductType></ProductType>
<ProductType></ProductType>
</FavoriteFossilProducts>
<AgeRange></AgeRange>
<PreferredEmailFormat></PreferredEmailFormat>
<SavedCreditCards>
<CreditCard>
<AcctNum></AcctNum>
<ExpiryDate></ExpiryDate>
</CreditCard>
<CreditCard>
<AcctNum></AcctNum>
<ExpiryDate></ExpiryDate>
</CreditCard>
</SavedCreditCards>
<PurchasedProductList>
<SKU></SKU>
<SKU></SKU>
</PurchasedProductList>
<OrderHistory>
<Orders>
<Order>
<Number></Number>
<TotalAmount></TotalAmount>
<Promotion></Promotion>
<TimePlaced></TimePlaced>
</Order>
<Order>
<Number></Number>
<TotalAmount></TotalAmount>
<Promotion></Promotion>
<TimePlaced></TimePlaced>
</Order>
</Orders>
</OrderHistory>
<WishLists>
<WishList>
<Name></Name>
<Description></Description>
<DateCreated></DateCreated>
<LastUpdate></LastUpdate>
<IsDefault></IsDefault>
<Items>
<Item>
<Quantity></Quantity>
<PartNumber></PartNumber>
<DateCreated></DateCreated>
<LastUpdate></LastUpdate>
</Item>
<Item>
<Quantity></Quantity>
<PartNumber></PartNumber>
<DateCreated></DateCreated>
<LastUpdate></LastUpdate>
</Item>
</Items>
</WishList>
<WishList>
<Name></Name>
<Description></Description>
<DateCreated></DateCreated>
<LastUpdate></LastUpdate>
<IsDefault></IsDefault>
<Items>
<Item>
<Quantity></Quantity>
<PartNumber></PartNumber>
<DateCreated></DateCreated>
<LastUpdate></LastUpdate>
</Item>
<Item>
<Quantity></Quantity>
<PartNumber></PartNumber>
<DateCreated></DateCreated>
<LastUpdate></LastUpdate>
</Item>
</Items>
</WishList>
</WishLists>
</CustomerData>
</Customer>'
DECLARE xml_cursor CURSOR FOR
SELECT FirstName , LastName , Gender , City , [State]
FROM #example_data
OPEN xml_cursor
FETCH NEXT FROM xml_cursor into #FirstName, #LastName, #Gender, #City, #State
WHILE ##fetch_status = 0
BEGIN
SET #xml = #customer_xml
SET #xml.modify('
insert <FirstName>{ xs:string(sql:variable("#FirstName")) }</FirstName>
before (/Customer/CustomerData/FirstName)[1]
')
SET #xml.modify('
delete /Customer/CustomerData/FirstName[2]
')
SET #xml.modify('
insert <LastName>{ xs:string(sql:variable("#LastName")) }</LastName>
before (/Customer/CustomerData/LastName)[1]
')
SET #xml.modify('
delete /Customer/CustomerData/LastName[2]
')
SET #xml.modify('
insert <Gender>{ xs:string(sql:variable("#Gender")) }</Gender>
before (/Customer/CustomerData/Gender)[1]
')
SET #xml.modify('
delete /Customer/CustomerData/Gender[2]
')
SET #xml.modify('
insert <City>{ xs:string(sql:variable("#City")) }</City>
before (/Customer/CustomerData/Addresses/BillingAddress/City)[1]
')
SET #xml.modify('
delete /Customer/CustomerData/Addresses/BillingAddress/City[2]
')
SET #xml.modify('
insert <State>{ xs:string(sql:variable("#State")) }</State>
before (/Customer/CustomerData/Addresses/BillingAddress/State)[1]
')
SET #xml.modify('
delete /Customer/CustomerData/Addresses/BillingAddress/State[2]
')
select #xml
FETCH NEXT FROM xml_cursor into #FirstName, #LastName, #Gender, #City, #State
END
you can also use FLWOR which will allow you to generate the xml in one go by using a template and adding data only to the elements you want.
You won't need to create tables or stored procedures. For example:
declare #x xml
set #x=(select FirstName, LastName from kc_consumer for xml path('CustomerData'))
SELECT #x.query('
for $a in /CustomerData
return
<CustomerData>
<StoreID></StoreID>
<FirstName>{data($a/FirstName)}</FirstName>
<LastName>{data($a/LastName)}</LastName>
<Gender></Gender>
<BirthMonth></BirthMonth>
<BirthYear></BirthYear>
<BirthDay></BirthDay>
<IsEmployee></IsEmployee>
<customerID></customerID>
</CustomerData>
')
I'm just including a few nodes for readability, you just need to paste the rest of them.
Having trouble importing an xml date feild into sql server, the other feilds are fine. I have tried numerous way's but it always returns as null. Any help please
2014-02-18T12:15:21.357 is the issue
The XML is
<?xml version="1.0" encoding="utf-8"?>
<MISRoot xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/IGUK.Evolution.FieldToolLite.Lib.MIS">
<Claims>
<Claim>
<Amalgamation>
<ChannelSolutions />
<Name i:nil="true" />
</Amalgamation>
<Appointments>
<Appointment>
<Access />
<AccessGranted>true</AccessGranted>
<AppointmentId>320</AppointmentId>
<EnterTime>2014-02-18T12:15:21.357</EnterTime>
<LeaveTime i:nil="true" />
<Name i:nil="true" />
</Appointment>
</Appointments>
<CustomProducts />
<Id>1220</Id>
<Payments />
<Tasks />
</Claim>
</Claims>
</MISRoot>
THE SQL is
CREATE TABLE [dbo].[xmlImportAppointments](
[ClaimId] [int] not null,
[AppointmentAUTO] [int] not NULL,
[AppointmentId] [int] not NULL,
[EnterTime] [datetime] NULL,
[LeaveTime] [datetime] NULL,
[AccessGranted] [nchar](20) NULL,
) ON [PRIMARY]
GO
WITH XMLNAMESPACES(DEFAULT 'http://schemas.datacontract.org/2004/07/IGUK.Evolution.FieldToolLite.Lib.MIS')
INSERT INTO xmlImportAppointments
(ClaimId, AppointmentAUTO, AppointmentId, EnterTime, LeaveTime, AccessGranted)
SELECT
ClaimId = xmldata.value('(Claim/Id)[1]', 'int'),
AppointmentAUTO = xmldata.value('(Claim/Appointments/Appointment/AppointmentId)[1]', 'int'),
AppointmentId = xmldata.value('(Claim/Appointments/Appointment/AppointmentId)[1]', 'int'),
EnterTime = xmldata.value('(Claims/Appointment/Appointments/EnterTime)[1]', 'datetime'),
LeaveTime = xmldata.value('(Claims/Appointment/Appointments/EnterTime)[1]', 'datetime'),
AccessGranted = xmldata.value('(Claim/Appointments/Appointment/AccessGranted)[1]', 'NCHAR(20)')
FROM
(SELECT CAST(x AS XML)
FROM OPENROWSET(BULK '\\XMLTest\increment.xml',
SINGLE_BLOB) AS T(x)) AS T(x)
CROSS APPLY
x.nodes('/MISRoot/Claims') AS X(xmldata);
SELECT * FROM xmlImportAppointments
You had a problem with your XQuery I had copied your File into a XML variable and was able to retrieve using the following query.
DECLARE #MyXMLVariable XML =
'<?xml version="1.0" encoding="utf-8"?>
<MISRoot xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/IGUK.Evolution.FieldToolLite.Lib.MIS">
<Claims>
<Claim>
<Amalgamation>
<ChannelSolutions />
<Name i:nil="true" />
</Amalgamation>
<Appointments>
<Appointment>
<Access />
<AccessGranted>true</AccessGranted>
<AppointmentId>320</AppointmentId>
<EnterTime>2014-02-18T12:15:21.357</EnterTime>
<LeaveTime i:nil="true" />
<Name i:nil="true" />
</Appointment>
</Appointments>
<CustomProducts />
<Id>1220</Id>
<Payments />
<Tasks />
</Claim>
</Claims>
</MISRoot>';
WITH XMLNAMESPACES(DEFAULT 'http://schemas.datacontract.org/2004/07/IGUK.Evolution.FieldToolLite.Lib.MIS')
SELECT #MyXMLVariable.value('(MISRoot/Claims/Claim/Appointments/Appointment/EnterTime)[1]','DATETIME')
You did not specify the full correct path to EnterTime
'(MISRoot/Claims/Claim/Appointments/Appointment/EnterTime)[1]' --Correct
'(Claims/Appointment/Appointments/EnterTime)[1]' --Yours
Appointment is child of Appointments not the other way around and Claim is a child of Claims best way to do this is to look at Open tags and closed tags