Updating multiple XML columns using single update in SQL Server - sql-server

I would like to update a table_A with new values for (AcresDist1, txtAcresDist1, txtAcresDist1Total) XML columns from a second table_B.
The column P_XML is of XML type. I know how to update a single column at once, but I would like to know how to update multiple columns in the XML using a single update statement. Thanks
SQL code:
UPDATE S
SET
P_XML.modify( N'replace value of (/FormValue/f1152_F1/Field[(id/text())[1]="AcresDist1"]/value/text())[1] with sql:column(''T.AcresDist1'')' )
, P_XML.modify( N'replace value of (/FormValue/f1152_F1/Field[(id/text())[1]="txtAcresDist1"]/value/text())[1] with sql:column(''T.txtAcresDist'')' )
, P_XML.modify( N'replace value of (/FormValue/f1152_F1/Field[(id/text())[1]="txtAcresDist1Total"]/value/text())[1] with sql:column(''T.txtAcresDist1Total'')' )
FROM
Table_A AS S
INNER JOIN
Table_B AS T ON s.P_NO = t.P_Number
AND s.FAC_RID = t.Fac_RID;
Here is the sample xml as requested. Thank you.
<FormValue>
<f1152>
<field>
<id>f1152_MainForm</id>
<value />
<tag />
<visible>true</visible>
<history>|09/28/2017 10:50:26 AM||</history>
<description />
<comment />
</field>
<field>
<id>txt_rdoCoverage</id>
<value>Development</value>
<tag />
<visible>false</visible>
<history>|09/28/2017 10:50:26 AM||</history>
<description />
<comment />
</field>
</f1152>
<f1152_F1>
<field>
<id>txtAcresDist1</id>
<value>1.2</value>
<tag />
<visible>false</visible>
<history>|09/28/2017 3:08:14 AM||</history>
<description />
<comment />
</field>
<field>
<id>txtAcresDist1Total</id>
<value>200</value>
<tag />
<visible>false</visible>
<history>|09/28/2017 3:08:14 AM||</history>
<description />
<comment />
</field>
</f1152_F1>

Related

How to update empty XML node in MSSQL

I want to update empty XML variable in MSSQL
i try every solutions like replace, outer apply , modify but nothing working
please help me find a solutions
<ArrayOfField xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Field>
<FieldType>1</FieldType>
<DataType>1</DataType>
<Label>department</Label>
<Name>department</Name>
<Description />
<Min />
<Max />
<DefaultValue />
<Required>0</Required>
<SelectItems />
<Formula />
<DataSourceUID xsi:nil="true" />
<TrueText />
<FalseText />
<UnconfirmtyRule xsi:nil="true" />
<UnconfirmtyRequired xsi:nil="true" />
<UnconfirmityFormUID xsi:nil="true" />
<ConfirmationStatus xsi:nil="true" />
<ConfirmationUserBasedType xsi:nil="true" />
<ConfirmationRightUsers />
<Newline>false</Newline>
<ColumnWith>12</ColumnWith>
<Offset>0</Offset>
</Field>
<Field>
<FieldType>1</FieldType>
<DataType>4</DataType>
<Label>Test</Label>
<Name>test</Name>
<Description />
<Min />
<Max />
<DefaultValue />
<Required>0</Required>
<SelectItems />
<Formula />
<TrueText />
<FalseText />
<UnconfirmtyRule xsi:nil="true" />
<UnconfirmtyRequired xsi:nil="true" />
<UnconfirmityFormUID xsi:nil="true" />
<ConfirmationStatus xsi:nil="true" />
<ConfirmationUserBasedType xsi:nil="true" />
<ConfirmationRightUsers />
<Newline>false</Newline>
<ColumnWith>12</ColumnWith>
<Offset>0</Offset>
</Field>
</ArrayOfField>
I want update DefaultValue if DataType = 1
New DefaultValue like <DefaultValue>TODAY()<DefaultValue/>
I try this code but not update anything what is my mistake?
DECLARE #SearchType NVARCHAR(100)=N'1';
DECLARE #ReplaceWith NVARCHAR(100)=N'TODAY()';
UPDATE FormSchema
SET Fields.modify('replace value of
(/ArrayOfField
/Field[DataType=sql:variable("#SearchType")]
/DefaultValue/text())[1]
with sql:variable("#ReplaceWith")')
WHERE Fields.exist('/ArrayOfField
/Field[DataType=sql:variable("#SearchType")]')=1;
You need to use different XML modify operations depending on whether the target element is empty or not (i.e.: it contains no text as opposed to being xsi:nil="true"). For example...
--
-- Setup data...
--
create table dbo.FormSchema (
Fields xml
);
insert dbo.FormSchema (Fields) values
(N'<ArrayOfField>
<Field>
<DataType>1</DataType>
<DefaultValue>Hello, world!</DefaultValue>
</Field>
<Field>
<DataType>2</DataType>
<DefaultValue />
</Field>
</ArrayOfField>'),
(N'<ArrayOfField>
<Field>
<DataType>1</DataType>
<DefaultValue />
</Field>
<Field>
<DataType>3</DataType>
<DefaultValue />
</Field>
</ArrayOfField>');
--
-- Perform updates...
--
DECLARE
#SearchType NVARCHAR(100) = N'1',
#ReplaceWith NVARCHAR(100) = N'TODAY()';
UPDATE dbo.FormSchema
SET Fields.modify('
replace value of (/ArrayOfField/Field[DataType=sql:variable("#SearchType")]/DefaultValue/text())[1]
with sql:variable("#ReplaceWith")
')
WHERE Fields.exist('(/ArrayOfField/Field[DataType=sql:variable("#SearchType")]/DefaultValue/text())[1]')=1;
UPDATE dbo.FormSchema
SET Fields.modify('
insert text{sql:variable("#ReplaceWith")}
into (/ArrayOfField/Field[DataType=sql:variable("#SearchType")]/DefaultValue)[1]
')
WHERE Fields.exist('(/ArrayOfField/Field[DataType=sql:variable("#SearchType")]/DefaultValue)[1]')=1
AND Fields.exist('(/ArrayOfField/Field[DataType=sql:variable("#SearchType")]/DefaultValue/text())[1]')=0;
--
-- Check results...
--
SELECT * FROM dbo.FormSchema;
Which yields the results:
Fields
<ArrayOfField><Field><DataType>1</DataType><DefaultValue>TODAY()</DefaultValue></Field><Field><DataType>2</DataType><DefaultValue /></Field></ArrayOfField>
<ArrayOfField><Field><DataType>1</DataType><DefaultValue>TODAY()</DefaultValue></Field><Field><DataType>3</DataType><DefaultValue /></Field></ArrayOfField>

SQL Server xml query doesn't return expected result

I have a column in my database FlowDetailParameter with XML Type .My table has one column FlowDetailParameter and 3 rows with these data :
row 1
<ArrayOfFlowDetailParameters xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<FlowDetailParameters>
<DepartmentId>7</DepartmentId>
<UserId>6</UserId>
<Username>4</Username>
<FullName>کارشناس معاینه فنی</FullName>
<ConfirmDateTime>2018-11-01T10:45:29.7371421+03:30</ConfirmDateTime>
<Comment>اولین IP تاییدی</Comment>
<Status>Accept</Status>
</FlowDetailParameters>
<FlowDetailParameters>
<DepartmentId>3</DepartmentId>
<UserId xsi:nil="true" />
<Username />
<FullName />
<ConfirmDateTime xsi:nil="true" />
<Comment />
<Status>Pending</Status>
<AttachmentId />
</FlowDetailParameters>
</ArrayOfFlowDetailParameters>
row 2
<ArrayOfFlowDetailParameters xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<FlowDetailParameters>
<DepartmentId>7</DepartmentId>
<UserId>6</UserId>
<Username>4</Username>
<FullName>کارشناس معاینه فنی</FullName>
<ConfirmDateTime>2018-11-01T10:45:40.437481+03:30</ConfirmDateTime>
<Comment>دومین IP تاییدی</Comment>
<Status>Accept</Status>
</FlowDetailParameters>
<FlowDetailParameters>
<DepartmentId>3</DepartmentId>
<UserId xsi:nil="true" />
<Username />
<FullName />
<ConfirmDateTime xsi:nil="true" />
<Comment />
<Status>Pending</Status>
<AttachmentId />
</FlowDetailParameters>
</ArrayOfFlowDetailParameters>
row 3
<ArrayOfFlowDetailParameters xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<FlowDetailParameters>
<DepartmentId>7</DepartmentId>
<UserId xsi:nil="true" />
<Username />
<FullName />
<ConfirmDateTime xsi:nil="true" />
<Comment />
<Status>Pending</Status>
<AttachmentId />
</FlowDetailParameters>
<FlowDetailParameters>
<DepartmentId>3</DepartmentId>
<UserId xsi:nil="true" />
<Username />
<FullName />
<ConfirmDateTime xsi:nil="true" />
<Comment />
<Status />
<AttachmentId />
</FlowDetailParameters>
</ArrayOfFlowDetailParameters>
I want to find the departmentId=3 and status=Pending ,so the expected result should return 2 rows .So here is my query :
select Requests.* from Requests
where
((SELECT count(*)
FROM Requests t
CROSS APPLY t.FlowDetailParameter.nodes ('/ArrayOfFlowDetailParameters/FlowDetailParameters') x(v)
where x.v.value('(DepartmentId/text())[1]', 'bigint')=3 and x.v.value('(Status/text())[1]', 'varchar(50)') = 'Pending') >0)
But my query returns all rows (3 rows) why ?
First to answer your question "why?":
Your sub-query is not a correlated sub-query. There is no connection to the current row from the outer SELECT. So - assuming there is at least 1 row fulfilling your condition - this will always provide a count>0.
Although your approach can be corrected, I'd suggest to use the XML-method .exist() and provide the filter as XPath/XQuery:
SELECT *
FROM Requests r
WHERE r.FlowDetailParameter.exist(N'/ArrayOfFlowDetailParameters
/FlowDetailParameters[(DepartmentId/text())[1]=3
and (Status/text())[1]="Pending"]')=1;
This will check for the existance of any <FlowDetailParameters> for the given condition.
If you want to introduce the filter dynamically, you can use sql:variable() or sql:column() instead of 3 and "Pending"
DECLARE #depId INT=3;
DECLARE #status VARCHAR(100)='Pending';
SELECT *
FROM Requests r
WHERE r.FlowDetailParameter.exist(N'/ArrayOfFlowDetailParameters
/FlowDetailParameters[(DepartmentId/text())[1]=sql:variable("#depId")
and (Status/text())[1]=sql:variable("#status")]')=1

SQL Server xml query can't return expected result

I have this xml data in my table as you can see :
<ArrayOfFlowDetailParameters xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<FlowDetailParameters>
<DepartmentId>23</DepartmentId>
<UserId xsi:nil="true" />
<Username />
<FullName />
<ConfirmDateTime xsi:nil="true" />
<Comment />
<Status>Pending</Status>
<AttachmentId />
</FlowDetailParameters>
<FlowDetailParameters>
<DepartmentId>22</DepartmentId>
<UserId xsi:nil="true" />
<Username />
<FullName />
<ConfirmDateTime xsi:nil="true" />
<Comment />
<Status>Pending</Status>
<AttachmentId />
</FlowDetailParameters>
<FlowDetailParameters>
<DepartmentId>7</DepartmentId>
<UserId xsi:nil="true" />
<Username />
<FullName />
<ConfirmDateTime xsi:nil="true" />
<Comment />
<Status>Pending</Status>
<AttachmentId />
</FlowDetailParameters>
<FlowDetailParameters>
<DepartmentId>18</DepartmentId>
<UserId xsi:nil="true" />
<Username />
<FullName />
<ConfirmDateTime xsi:nil="true" />
<Comment />
<Status>Pending</Status>
<AttachmentId />
</FlowDetailParameters>
</ArrayOfFlowDetailParameters>
when i want to find the departmentid with value=22 my query returns 0 result but when i search value=23 it returns 1 result i think it is because of [1].
declare #departmentId nvarchar(max)
set #departmentId=22
select Requests.* from Requests
where
and (FlowDetailParameter.value('(/ArrayOfFlowDetailParameters/FlowDetailParameters/DepartmentId/text())[1]','bigint') = #departmentId )
It sounds like you're trying to query a list of requests where the FlowDetailParameter column's XML contains a record where the DepartmentId matches your #departmentId variable, right?
The [1] in your query specifies to only check the first occurrence of DepartmentId in each row's FlowDetailParameter XML. You won't get a match unless the first DepartmentId in the XML matches your parameter.
Instead, you can use the following query to find all requests that have a FlowDetailParameter matching the #departmentid variable using the nodes() method.
SELECT r.*
FROM #Requests r
WHERE EXISTS (SELECT *
FROM r.FlowDetailParameter.nodes('/ArrayOfFlowDetailParameters/FlowDetailParameters/DepartmentId') as Parms(DepartmentId)
WHERE DepartmentId.value('.', 'bigint') = #departmentid)

How can i generate a XML without repeating an field twice

I'm trying to generated a xml using the below code. But I'm not satisfied with the output result. Below code I'm using the cursor to get the ids for the xml to be generated and update in another table. Any help is appreciated and i'm new to xml. Thanks
DECLARE #xml_var XML;
DECLARE #ID INT;
DECLARE XML_CURSOR CURSOR FOR
SELECT id
FROM xml_temp_table
WHERE id IS NOT NULL;
OPEN XML_CURSOR;
FETCH NEXT
FROM XML_CURSOR
INTO #ID;
WHILE ##FETCH_STATUS = 0
BEGIN
SET #xml_var =
(
SELECT
(
SELECT 'Type' AS ID,
'Initial' AS VALUE,
'' AS TAG,
'true' AS VISIBLE,
Getdate() AS HISTORY,
'' AS DESCRIPTION,
'' AS COMMENT
FROM XML_TABLE d
WHERE D.XML_ID = #ID FOR XML PATH('field'),
TYPE ) AS 'field',
(
SELECT 'OwnerName' AS ID,
'Testing_XML' AS VALUE,
'' AS TAG,
'true' AS VISIBLE,
Getdate() AS HISTORY,
'' AS DESCRIPTION,
'' AS COMMENT
FROM XML_TABLE d
WHERE D.XML_ID = #ID FOR XML PATH('field'),
TYPE ) AS 'field'
FROM XML_TABLE p
WHERE P.XML_ID = #ID FOR XML PATH('Material'),
ROOT('FormValue') );
UPDATE S
SET S.XML_COL = #xml_var,
FROM LOCATION_TABLE_XML S
WHERE S.ID = #ID;
FETCH NEXT
FROM XML_CURSOR
INTO #ID;
END;
The result i'm getting is this way
<FormValue>
<Material>
<field> ----- i dont want this
<field>
<id>Type</id>
<value>Initial</value>
<tag />
<visible>true</visible>
<history>2016-11-08T16:53:16.440</history>
<description />
<comment />
</field>
<field>
<id>OwnerName</id>
<value>Testing_XML</value>
<tag />
<visible>true</visible>
<history>2016-11-08T16:53:16.440</history>
<description />
<comment />
</field>
</field> ---- i dont want this
</Material>
</FormValue>
But I want the result in this way
<FormValue>
<Material>
<field>
<id>Type</id>
<value>Initial</value>
<tag />
<visible>true</visible>
<history>2016-11-08T16:53:16.440</history>
<description />
<comment />
</field>
<field>
<id>OwnerName</id>
<value>Testing_XML</value>
<tag />
<visible>true</visible>
<history>2016-11-08T16:53:16.440</history>
<description />
<comment />
</field>
</Material>
</FormValue>
Might be enough to let the AS 'field' away. Your FOR XML PATH('field') will wrap each row with a <field> element.
The XML returning sub-selects can be seen as scalar values handled like a normal column. By providing a column alias this whole node gets a name and this name is again translated into a wrapping <field> element.
You can either erase this, or replace it with AS [node()] or with AS [*]

xml.value() method in SQL Server (Getting a value inside an XML query)

I have an XML Query like this:
<ChangeSet xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Change DateTime="2011-12-02T09:01:58.3615661-08:00" UserId="3123">
<Table ChangeType="Insert" Name="EVNT_LN_AFF">
<Keys>
<Key FieldName="DIR_CD" Value="NB" />
<Key FieldName="LN_ID" Value="A" />
<Key FieldName="EVNT_ID" Value="10T000289" />
</Keys>
<ChangedFields>
<Field FieldName="DIR_CD" Previous="" Current="NB" />
<Field FieldName="LN_ID" Previous="" Current="A" />
<Field FieldName="EVNT_ID" Previous="" Current="10T000289" />
<Field FieldName="UD_DTTM" Previous="" Current="12/2/2011 9:01:59 AM" />
<Field FieldName="UD_USER_ID" Previous="" Current="3123" />
</ChangedFields>
</Table>
(The query goes on)
Now I want to use a statement like this:
SELECT TOP 1000 [CHG_LOG_ID]
, [EVNT_ID]
, [DATA_XML_TXT]
, [UD_DTTM]
FROM [MY_PROJ].[dbo].[EVNT_CHG_LOG]
WHERE DATA_XML_TXT.value('(/ChangeSet/Change/Table/ChangedFields/UD_USER_ID)[0]','varchar(50)') like '%3123%'
But when I execute the query, I don't get any results.
I tested the following XQuery, and it should give you what you need:
SELECT TOP 1000 [CHG_LOG_ID]
, [EVNT_ID]
, [DATA_XML_TXT]
, [UD_DTTM]
FROM [MY_PROJ].[dbo].[EVNT_CHG_LOG]
WHERE DATA_XML_TXT.value('(/ChangeSet/Change/Table/ChangedFields/Field[#FieldName="UD_USER_ID"]/#Current)[1]','varchar(50)') like '%3123%'
Note: Indexing for XQuery starts at 1 instead of 0

Resources