XQuery SQL Extract text value from a child element of a specific node - sql

I'm struggling with the following situation: I need to extract that '10000' after
...name="stateid"> <from>10000</from>
I've managed to extract some that I need from the first node audittrail
SELECT ref.value ('#datetime', 'nvarchar(364)') as [LastTimeActioned],
ref.value ('#changedby', 'nvarchar(364)') as [Actioned_By]
FROM Audit
CROSS APPLY audit.Xml.nodes ('/audittrail') R(ref)
<audittrail id="137943" datetime="29-Feb-2016 15:42:06" changedby="quality" type="update">
<fields>
<field id="10022" name="Content Control">
<mergedValue>dsad</mergedValue>
<from />
<to>dsad</to>
</field>
<field id="10027" name="Document Controller">
<mergedValue>quality</mergedValue>
<from />
<to>quality</to>
</field>
<field id="10028" name="Document Owner">
<mergedValue>quality</mergedValue>
<from />
<to>quality</to>
</field>
<field id="10029" name="Document Type">
<mergedValue>Contract/Agreement</mergedValue>
<from />
<to>Contract/Agreement</to>
</field>
<field id="10067" name="StateId">
<from>10000</from>
<to>10000</to>
</field>
....
</fields>
</audittrail>

You're looking for the Xpath:
(fields/field[#name="StateId"]/from)[1]
i.e. Find me the "fields/field" element with the attribute name of value StateId, and select the contents of the immediate child from element:
SELECT
ref.value ('#datetime', 'nvarchar(364)') as [LastTimeActioned],
ref.value ('#changedby', 'nvarchar(364)') as [Actioned_By],
ref.value ('(fields/field[#name="StateId"]/from)[1]', 'integer') as StateIdFrom
FROM Audit
CROSS APPLY audit.Xml.nodes ('/audittrail') R(ref)
SqlFiddle Here
Note that you need to explicitly select the first text element result in XQuery (hence the extra parenthesis() and [1])
More technically correctly, you could also restrict the selection to the text() of the child from, i.e.:
(fields/field[#name="StateId"]/from/text())[1]

Related

Update 3rd level deep field value in an XML using xQuery

I have the following sample XML and I am looking to Update:
AttendeeID to 7878 (will be a sql variable) where sequence = 1 (will be a sql variable)
Expected output is to see 7878 in the AttendeeID field's value. When I run any of the 2 options I tried, it does not yield the correct result. For Eg. Delete works but the element is not added. Replace value does not update the value.
Any inputs are highly appreciated. Thank you.
--------XML ---------------------------
DECLARE #cartXML XML =
'<OBJECT CLASS="Test1" ID="-1" FULL="FULL" VERSION="1">
<FIELD NAME="OrderDate">20220619</FIELD>
<FIELD NAME="OrderParty">Individual</FIELD>
<FIELD NAME="ShipToID">34567</FIELD>
<FIELD NAME="ShipToAddress1">123 Test Street</FIELD>
<FIELD NAME="ShipToCity">TestCity</FIELD>
<FIELD NAME="ShipToState">IL</FIELD>
<FIELD NAME="ShipTocountry">USA</FIELD>
<FIELD NAME="TaxNumber">444</FIELD>
<FIELD NAME="DiscountCode">Summer22</FIELD>
<SUBTYPE NAME="SubType1">
<OBJECT NAME="SubType111" ID="-1">
<FIELD NAME="TestID">-1</FIELD>
<FIELD NAME="Sequence">1</FIELD>
<FIELD NAME="ParentSequence">-1</FIELD>
<FIELD NAME="ExtID">-1</FIELD>
<FIELD NAME="ExtName">ABC</FIELD>
</OBJECT>
<OBJECT NAME="SubType111" ID="-1">
<FIELD NAME="TestID">-1</FIELD>
<FIELD NAME="Sequence">2</FIELD>
<FIELD NAME="ParentSequence">1</FIELD>
<FIELD NAME="ExtID">-1</FIELD>
<FIELD NAME="ExtName">DEF</FIELD>
<FIELD NAME="__ExtendedData"><OBJECT
CLASS="Meet123" ID="-1" FULL="FULL"
VERSION="1"><FIELD
NAME="OrderDetailID">-1</FIELD><FIELD
NAME="OrderID">-1</FIELD><FIELD
NAME="Sequence">0</FIELD><FIELD
NAME="AttendeeID">123</FIELD><FIELD NAME="AttendeeID_Name">Test, Mark/I
H 6</FIELD><FIELD
NAME="ShowList">1</FIELD><FIELD
NAME="BdgeName">Mark</FIELD><FIELD
NAME="BadgeCompanyName">I H 6</FIELD>
</OBJECT></FIELD>
</OBJECT>
<OBJECT NAME="SubType111" ID="-1">
<FIELD NAME="TestID">-1</FIELD>
<FIELD NAME="Sequence">3</FIELD>
<FIELD NAME="ParentSequence">1</FIELD>
<FIELD NAME="ExtID">-1</FIELD>
<FIELD NAME="ExtName">GHI</FIELD>
</OBJECT>
</SUBTYPE>
<SUBTYPE NAME="SubType2"/>
<SUBTYPE NAME="SubType3"/>
</OBJECT>';
-----------------------SQL -----------------------
select #cartXML as originalXML
DECLARE #ID as int ,#productID as int, #attendeeId as int = 7878,
#sequenceId as int, #orderLineXML as XML , #ExtendedAttrDetail as XML
SET #sequenceId = 2
select #orderlineXML = c.query('.'), #ExtendedAttrDetail = w.query('.') from
#cartXML.nodes('/OBJECT/SUBTYPE/OBJECT[FIELD[#NAME="Sequence"]/text()=sql:variable("#sequenceId")]') t1(c)
Cross APPLY (VALUES(TRY_CAST(c.query('FIELD[#NAME="__ExtendedData"]').value('.','NVARCHAR(MAX)') AS XML)))AS t2(w)
-----This works..But I am looking to alter #cartXML as it contains the entire XML
SET #ExtendedAttrDetail.modify('replace value of
(/OBJECT/FIELD[#NAME="AttendeeID"]/text())[1]
with sql:variable("#attendeeId")')
--select #ExtendedAttrDetail
------- Option 1( Preferred)---does not work--
SET #cartXML.modify ('replace value of
(/OBJECT/SUBTYPE/OBJECT[FIELD[#NAME="Sequence"]/text()=sql:variable("#sequenceId")]/FIELD[#NAME="__ExtendedData"]/OBJECT/FIELD[#NAME="AttendeeID"]/text())[1] with sql:variable("#attendeeId")')
select #cartXML as ModifiedDirectly
---Option 2 (Insert does not add correctly )
--SET #cartXML.modify('delete
--/OBJECT/SUBTYPE/OBJECT[FIELD[#NAME="Sequence"]/text()=sql:variable("#sequenceId")]
--/FIELD[#NAME="__ExtendedData"]');
--SET #cartXML.modify('insert sql:variable("#ExtendedAttrDetail") into
--(/OBJECT/SUBTYPE/OBJECT[FIELD[#NAME="Sequence"]/text()=sql:variable("#sequenceId")])
--[1]');
--SELECT #cartXML as UpdatedXL;
Please try the following solution.
The issue is that the XML fragment in question is encoded.
SQL
DECLARE #cartXML XML =
N'<OBJECT CLASS="Test1" ID="-1" FULL="FULL" VERSION="1">
<FIELD NAME="OrderDate">20220619</FIELD>
<FIELD NAME="OrderParty">Individual</FIELD>
<FIELD NAME="ShipToID">34567</FIELD>
<FIELD NAME="ShipToAddress1">123 Test Street</FIELD>
<FIELD NAME="ShipToCity">TestCity</FIELD>
<FIELD NAME="ShipToState">IL</FIELD>
<FIELD NAME="ShipTocountry">USA</FIELD>
<FIELD NAME="TaxNumber">444</FIELD>
<FIELD NAME="DiscountCode">Summer22</FIELD>
<SUBTYPE NAME="SubType1">
<OBJECT NAME="SubType111" ID="-1">
<FIELD NAME="TestID">-1</FIELD>
<FIELD NAME="Sequence">1</FIELD>
<FIELD NAME="ParentSequence">-1</FIELD>
<FIELD NAME="ExtID">-1</FIELD>
<FIELD NAME="ExtName">ABC</FIELD>
</OBJECT>
<OBJECT NAME="SubType111" ID="-1">
<FIELD NAME="TestID">-1</FIELD>
<FIELD NAME="Sequence">2</FIELD>
<FIELD NAME="ParentSequence">1</FIELD>
<FIELD NAME="ExtID">-1</FIELD>
<FIELD NAME="ExtName">DEF</FIELD>
<FIELD NAME="__ExtendedData"><OBJECT
CLASS="Meet123" ID="-1" FULL="FULL"
VERSION="1"><FIELD
NAME="OrderDetailID">-1</FIELD><FIELD
NAME="OrderID">-1</FIELD><FIELD
NAME="Sequence">0</FIELD><FIELD
NAME="AttendeeID">123</FIELD><FIELD NAME="AttendeeID_Name">Test, Mark/I
H 6</FIELD><FIELD
NAME="ShowList">1</FIELD><FIELD
NAME="BdgeName">Mark</FIELD><FIELD
NAME="BadgeCompanyName">I H 6</FIELD>
</OBJECT></FIELD>
</OBJECT>
<OBJECT NAME="SubType111" ID="-1">
<FIELD NAME="TestID">-1</FIELD>
<FIELD NAME="Sequence">3</FIELD>
<FIELD NAME="ParentSequence">1</FIELD>
<FIELD NAME="ExtID">-1</FIELD>
<FIELD NAME="ExtName">GHI</FIELD>
</OBJECT>
</SUBTYPE>
<SUBTYPE NAME="SubType2"/>
<SUBTYPE NAME="SubType3"/>
</OBJECT>';
DECLARE #ExtendedData XML
, #attendeeId INT = 770;;
-- Step #1: select XML fragment in question as real XML data type
SELECT #ExtendedData = w
FROM #cartxml.nodes('/OBJECT/SUBTYPE/OBJECT[#ID="-1"]') as t1(c)
CROSS APPLY (VALUES(TRY_CAST(c.query('FIELD[#NAME="__ExtendedData"]').value('.','NVARCHAR(MAX)') AS XML))) AS t2(w)
WHERE w.exist('/OBJECT[#CLASS="Meet123"]') = 1;
-- Step #2: remove encoded XML fragment
SET #cartXML.modify('replace value of (/OBJECT/SUBTYPE[#NAME="SubType1"]/OBJECT/FIELD[#NAME="__ExtendedData"]/text())[1]
with ""');
-- Step #3: modify AttendeeID
SET #ExtendedData.modify('replace value of
(/OBJECT/FIELD[#NAME="AttendeeID"]/text())[1]
with sql:variable("#attendeeId")');
-- Step #4: insert real XML fragment
SET #cartXML.modify('insert sql:variable("#ExtendedData") into
(/OBJECT/SUBTYPE[#NAME="SubType1"]/OBJECT/FIELD[#NAME="__ExtendedData"])[1]');
-- test
SELECT #cartXML;

How to keep the order of the records added in a many2many field the way I wrote them?

I want to keep the order of the records in the many2many field, the way I added them using the write method, but Odoo use the alphanumerical order by default and overwrote the order I put them in. How can I keep it in the same order when I wrote them, is that possible ?
Here is the model code:
# -*- coding: utf-8 -*-
from odoo import models, fields, api
class projet_richat(models.Model):
_inherit = 'project.task'
competence_ids = fields.Many2many('competence.competence',string='Compétences')
consultants=fields.Many2many('hr.employee', string="Consultants")
def search_comp(self):
if len(self.competence_ids) != 0:
consults=self.env['hr.employee'].sudo().search([])
list=[]
for cmp in self.competence_ids:
print(cmp.competence)
for cons in consults:
print(cons.name)
for c in cons.competences:
if c.competence.competence==cmp.competence:
list.append((cons.id,c.competence.competence,c.niveau))
sorted_by_level = sorted(list, key=lambda tup: tup[2], reverse=True)
print(sorted_by_level)
for sorted_cons in sorted_by_level:
self.write({'consultants': [[4, sorted_cons[0]]]})
and here is the view code:
<odoo>
<data>
<record model="ir.ui.view" id="project_inherit_form">
<field name="name">project.inherit.form</field>
<field name="model">project.task</field>
<field name="type">form</field>
<field name="inherit_id" ref="project.view_task_form2"/>
<field name="arch" type="xml">
<field name="user_ids" position="before">
<field name="competence_ids" widget="many2many_tags"/>
</field>
<field name="parent_id" position="after">
<field name="consultants">
<tree>
<field name="name"/>
</tree>
</field>
</field>
<button name="action_assign_to_me" position="after">
<button name="search_comp" string="Test" class="btn-primary"
type="object"
/>
</button>
</field>
</record>
</data>
</odoo>
Thanks in advance.
The many2many field will use the list view to show its content, the default order is defined by the _order attribute on the related model.
You can alter the default ordering by setting the default_order parameter on the tree tag
From the List view documentation:
default_orderoverrides the ordering of the view, replacing the model’s order (_order model attribute). The value is a comma-separated list of fields, postfixed by desc to sort in reverse order:
<tree default_order="sequence,name desc">
To keep the order you want, you can add an integer field sequence and use it to order records (_order='sequence') then in search_comp function set the sequence field value for each line

Odoo how to show detail table and in each cell select an option from a many2one field?

I explain how it should work: there must be a view where I can register the available schedule so that the students can enroll.
The problem is that every day of the week students can receive classes in different classrooms.
For example, Monday in classroom A, Tuesday in classroom B, etc.
I thought about creating a table as a master and another as a detail, and then put on detail the day of the week and a many2one field to choose the classroom.
But I have not succeeded, perhaps it is a logical error. If someone can guide me, I would really appreciate it.
Here code
Model of the master table(called Schedule)
class Schedule(models.Model):
_name = 'module_name.schedule'
_rec_name = 'id'
hi_id_niv_p = fields.Many2one('module_name.level',
string="English level", required=True) # fk
.......
.......
# falta !!! <- el detalle
# pruebas
x_classroom = fields.Many2many(
'module_name.detail_schedule')
Model of detail table(called )
class DetailSchedule(models.Model):
_name = 'module_name.detail_schedule'
# _rec_name = 'id'
# the next field is to save id of Schedule
dhi_id_hor_p = fields.Integer()
# day of the week
dhi_dia = fields.Selection([('1', 'Monday'), ('2', 'Tuesday'), (
'3', 'Wednesday'), ('4', 'Thursday'), ('5', 'Friday'), ('6', 'Saturday')], "Day")
# classroom
dhi_id_amb_p = fields.Many2one(
'module_name.classroom', string="Classroom", required=True)
VIEW
<!--Horario Idiomas Form -->
<record model="ir.ui.view" id="schedule_form_view">
<field name="name">schedule.form</field>
<field name="model">module_name.schedule</field>
<field name="arch" type="xml">
<form>
<sheet>
<group>
<field name="id" />
<field name="hi_id_niv_p" options="{'no_create':True,'no_open':True}"/>
<field name="hi_id_cur_p" options="{'no_create':True,'no_open':True}"/>
.....
</group>
<group>
<notebook>
<page name="english_classroom" string="Classroom">
<!-- Schedule detail -->
<!--
Here I want to show a table with columns that represent the days of the week, and in each cell you can display the classrooms
-->
<div>
<field name="x_classroom">
<tree editable="bottom" >
<field name="dhi_dia" /> <!-- here day of the week -->
<field name="dhi_id_amb_p" /> <!-- classroom -->
</tree>
</field>
</div>
</page>
</notebook>
</group>
</sheet>
</form>
</field>
</record>

Populate other field with value

I have a test many2one field. When it is populated I want the partner_id field to use the partner associated with that field. Following is not working:
<field name="partner_id" required="1"/>
<field name="x_test" context="{'partner_id': parent.partner_id}" />
you should try this :
<field name="x_test" context="{'default_partner_id': partner_id}" />
I don't know what you mean by parent.partner_id this works if you have a field named parent in the same view.
i assume you wanna put same value of partner_id in x_test field, then use related field
partner_id = fields.Many2one('res.partner', string="partner")
x_test = fields.Many2one('res.partner',related='partner_id', string="X Test")
in XML
<field name="partner_id" required="1"/>
<field name="x_test" />

How to hide/show fields on selecting option in openerp

I have a selection field and text field
'work': fields.selection([('tax', 'Tax Audit'), ('statutary',
'Statutary'), ('certificate', 'Certificate'), ('projection',
'Projections'), ('acount', 'Accounting'), ('others', 'Others'),
('roc', 'ROC Reg'), ('vat', 'VAT')], 'Nature Of Work'),
'details':fields.text('Details'),
<field name="work" select="0"/>
<field name="details" select="0"/>
Details field must be visible only on selection of 'roc' and 'vat'
how can I get this please help me
Try following:
<field name="details" attrs="{'invisible':[('work','not in',['roc','vat'])]}"/>