Where condition in Mondrian - mdx

MDX query to find the employee salary more then 5000
select
{
[Measures].[Total Employee],
[Measures].[Total Salary]
} on columns,
NON EMPTY
{
(
[Department].[All Department],
[Position].[All Position],
[Employee].[All Employee])
} on rows
from Salary
where
[Measures].[Total Salary]>5000
My schema
<Schema name="Foodmart">
<Cube name="Salary" visible="true" cache="true" enabled="true">
<Table name="employee" alias="">
</Table>
<Dimension type="StandardDimension" visible="true" foreignKey="department_id" name="Department">
<Hierarchy name="All Department" visible="true" hasAll="true" allMemberName="All Department" primaryKey="department_id" primaryKeyTable="department">
<Table name="department">
</Table>
<Level name="Dept" visible="true" column="department_description" uniqueMembers="true">
</Level>
</Hierarchy>
</Dimension>
<Dimension type="StandardDimension" visible="true" foreignKey="position_id" name="Position">
<Hierarchy name="All Position" visible="false" hasAll="true" allMemberName="All Position" primaryKey="position_id" primaryKeyTable="position">
<Table name="position">
</Table>
<Level name="position" visible="true" table="position" column="position_title" uniqueMembers="false">
</Level>
</Hierarchy>
</Dimension>
<Dimension type="StandardDimension" visible="true" name="Employee">
<Hierarchy name="All Employee" visible="true" hasAll="true" allMemberName="All Employee">
<Table name="employee" alias="">
</Table>
<Level name="New Level 0" visible="true" column="full_name" uniqueMembers="false">
</Level>
</Hierarchy>
</Dimension>
<Measure name="Total Salary" column="salary" aggregator="sum" visible="true">
</Measure>
<Measure name="Total Employee" column="employee_id" aggregator="distinct-count" visible="true">
</Measure>
</Cube>
</Schema>

I know if you're coming from slq it looks ok but the following is wrong:
WHERE
[Measures].[Total Salary]>5000
You could use the filter function inside the SELECT clause:
SELECT
{
[Measures].[Total Employee],
[Measures].[Total Salary]
} ON COLUMNS,
NON EMPTY
{
(
[Department].[All Department],
[Position].[All Position]
)
} ON ROWS
FROM [Salary]
WHERE FILTER(
[Employee].[All Employee].CHILDREN,
[Measures].[Total Salary]>5000
);
The above will be filtering employees whose total salary for all time is greater than 5000.
The filter could go around the complete cross set if you like the following but you'll get a list of all the respective employees returned:
SELECT
{
[Measures].[Total Employee],
[Measures].[Total Salary]
} ON COLUMNS,
NON EMPTY
FILTER(
{
(
[Department].[All Department],
[Position].[All Position],
[Employee].[All Employee].CHILDREN
)
}
,[Measures].[Total Salary]>5000
) ON ROWS
FROM [Salary];
Or use a HAVING clause across the whole set - although this is logically different that the above:
SELECT
{
[Measures].[Total Employee],
[Measures].[Total Salary]
} ON COLUMNS,
NON EMPTY
[Department].[All Department]
* [Position].[All Position],
* [Employee].[All Employee].CHILDREN
HAVING [Measures].[Total Salary]>5000 ON ROWS
FROM [Salary];
Edit
You can move the filter to a sub-cube if you still require the [All EmplyeeS] member on ROWS:
SELECT
{
[Measures].[Total Employee],
[Measures].[Total Salary]
} ON COLUMNS,
NON EMPTY
[Department].[All Department]
*[Position].[All Position]
*[Employee].[All Employee]
ON ROWS
FROM
(
SELECT
FILTER(
[Employee].[All Employee].CHILDREN,
[Measures].[Total Salary]>5000
) ON 0
FROM [Salary]
);

I guess you are running into space/memory issues. If so, can you try the code below:
select
{
[Measures].[Total Employee],
[Measures].[Total Salary]
} on columns,
NON EMPTY
{
NonEmpty(
(
[Department].[All Department] *
[Position].[All Position] *
[Employee].[All Employee]
)
,[Measures].[Total Salary]
)
} having [Measures].[Total Salary] > 5000 on rows
from Salary
The NonEmpty function will remove the empty tuples while cross join.
EDIT 1
How about now?
with member [Measures].SalGrtrThan5000
as
IIF
(
[Measures].[Total Salary] > 5000,
1,
NULL
)
select
{
[Measures].[Total Employee],
[Measures].[Total Salary]
} on columns,
NON EMPTY
{
NonEmpty(
(
[Department].[All Department] *
[Position].[All Position] *
[Employee].[All Employee]
)
,[Measures].SalGrtrThan5000
)
}
on rows
from Salary
EDIT, using EXISTS
select
{
[Measures].[Total Employee],
[Measures].[Total Salary]
} on columns,
NON EMPTY
{
FILTER
(
EXISTS (
(
[Department].[All Department] *
[Position].[All Position] *
[Employee].[All Employee]
)
, , "SomeMeasureGroup"
) //EXISTS will remove non-empty tuples this way
, [Measures].[Total Salary] > 5000
)//Filters the set
}
on rows
from Salary
Replace "SomeMeasureGroup" with the actual name of measure group to which [Measures].[Total Salary] belongs. There is a cell-by-cell filter but with the use of EXISTS, hopefully it will be faster this time.

Related

Extract specific value from XML array (where FieldName = x)

Oracle 18c:
Test #1:
The following query works as expected. It selects values from XML (the XML is a clob column via a view).
Query:
select
cast(substr(extractvalue(a.column_value,'/Subtype/SubtypeCode'),1,255) as number(9,0)) as subtype_code,
substr(extractvalue(a.column_value,'/Subtype/SubtypeName'),1,255) as subtype_name,
substr(extractvalue(a.column_value,'/Subtype/FieldInfos/SubtypeFieldInfo/FieldName'),1,255) as field_name,
substr(extractvalue(a.column_value,'/Subtype/FieldInfos/SubtypeFieldInfo/DomainName'),1,255) as domain_name
from
sde.gdb_items_vw
cross join
xmlsequence(xmltype(definition).extract('/DETableInfo/Subtypes/Subtype')) a --https://community.oracle.com/tech/developers/discussion/4499629/at-what-version-did-the-table-keyword-for-table-collection-expressions-become-optional
where
name = 'INFRASTR.EVENTS_ONLY_1_ARRAY_VALUE'
SUBTYPE_CODE SUBTYPE_DESCRIPTION FIELD_NAME DOMAIN_NAME
------------ -------------------------------- ---------- --------------
0 ACTIVE TRANSPORTATION ACTIVITY ACTIVITY_ATN_1
1 GEODETIC CONTROL SURVEY MONUMENT ACTIVITY ACTIVITY_GCSM
2 MUNICIPAL STRUCTURES (BRIDGES) ACTIVITY ACTIVITY_MS
XML:
<?xml version="1.0" encoding="UTF-8"?>
<DETableInfo xmlns:typens="http://www.esri.com/schemas/ArcGIS/10.7" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="typens:DETableInfo">
<CatalogPath>\INFRASTR.BC_EVENTS</CatalogPath>
<Name>INFRASTR.BC_EVENTS</Name>
<ChildrenExpanded>false</ChildrenExpanded>
<DatasetType>esriDTTable</DatasetType>
<DSID>60337</DSID>
<Versioned>false</Versioned>
<CanVersion>true</CanVersion>
<ConfigurationKeyword />
<RequiredGeodatabaseClientVersion>10.0</RequiredGeodatabaseClientVersion>
<HasOID>true</HasOID>
<OIDFieldName>OBJECTID</OIDFieldName>
<GPFieldInfoExs xsi:type="typens:ArrayOfGPFieldInfoEx">
<GPFieldInfoEx xsi:type="typens:GPFieldInfoEx">
<Name>OBJECTID</Name>
<AliasName>OBJECTID</AliasName>
<ModelName>OBJECTID</ModelName>
<FieldType>esriFieldTypeOID</FieldType>
<IsNullable>false</IsNullable>
<DomainFixed>true</DomainFixed>
<Required>true</Required>
<Editable>false</Editable>
</GPFieldInfoEx>
<GPFieldInfoEx xsi:type="typens:GPFieldInfoEx">
<Name>ASSET_CLASS</Name>
<AliasName>ASSET_CLASS</AliasName>
<ModelName>ASSET_CLASS</ModelName>
<FieldType>esriFieldTypeSmallInteger</FieldType>
<DefaultValueNumeric>2</DefaultValueNumeric>
<IsNullable>true</IsNullable>
</GPFieldInfoEx>
<GPFieldInfoEx xsi:type="typens:GPFieldInfoEx">
<Name>ACTIVITY</Name>
<AliasName>ACTIVITY</AliasName>
<ModelName>ACTIVITY</ModelName>
<FieldType>esriFieldTypeString</FieldType>
<IsNullable>true</IsNullable>
</GPFieldInfoEx>
</GPFieldInfoExs>
<CLSID>{7A566981-C114-11D2-8A28-006097AFF44E}</CLSID>
<EXTCLSID />
<RelationshipClassNames xsi:type="typens:Names" />
<AliasName />
<ModelName />
<HasGlobalID>false</HasGlobalID>
<GlobalIDFieldName />
<RasterFieldName />
<ExtensionProperties xsi:type="typens:PropertySet">
<PropertyArray xsi:type="typens:ArrayOfPropertySetProperty" />
</ExtensionProperties>
<SubtypeFieldName>ASSET_CLASS</SubtypeFieldName>
<DefaultSubtypeCode>2</DefaultSubtypeCode>
<Subtypes xsi:type="typens:ArrayOfSubtype">
<Subtype xsi:type="typens:Subtype">
<SubtypeName>ACTIVE TRANSPORTATION</SubtypeName>
<SubtypeCode>0</SubtypeCode>
<FieldInfos xsi:type="typens:ArrayOfSubtypeFieldInfo">
<SubtypeFieldInfo xsi:type="typens:SubtypeFieldInfo">
<FieldName>ACTIVITY</FieldName>
<DomainName>ACTIVITY_ATN_1</DomainName>
</SubtypeFieldInfo>
</FieldInfos>
</Subtype>
<Subtype xsi:type="typens:Subtype">
<SubtypeName>GEODETIC CONTROL SURVEY MONUMENT</SubtypeName>
<SubtypeCode>1</SubtypeCode>
<FieldInfos xsi:type="typens:ArrayOfSubtypeFieldInfo">
<SubtypeFieldInfo xsi:type="typens:SubtypeFieldInfo">
<FieldName>ACTIVITY</FieldName>
<DomainName>ACTIVITY_GCSM</DomainName>
</SubtypeFieldInfo>
</FieldInfos>
</Subtype>
<Subtype xsi:type="typens:Subtype">
<SubtypeName>MUNICIPAL STRUCTURES (BRIDGES)</SubtypeName>
<SubtypeCode>2</SubtypeCode>
<FieldInfos xsi:type="typens:ArrayOfSubtypeFieldInfo">
<SubtypeFieldInfo xsi:type="typens:SubtypeFieldInfo">
<FieldName>ACTIVITY</FieldName>
<DomainName>ACTIVITY_MS</DomainName>
</SubtypeFieldInfo>
</FieldInfos>
</Subtype>
</Subtypes>
<ControllerMemberships xsi:type="typens:ArrayOfControllerMembership" />
<EditorTrackingEnabled>false</EditorTrackingEnabled>
<CreatorFieldName />
<CreatedAtFieldName />
<EditorFieldName />
<EditedAtFieldName />
<IsTimeInUTC>false</IsTimeInUTC>
<ChangeTracked>false</ChangeTracked>
<FieldFilteringEnabled>false</FieldFilteringEnabled>
<FilteredFieldNames xsi:type="typens:Names" />
</DETableInfo>
Screenshot from the application.
Test #2:
Regarding the 3rd and 4th columns in the query:
In the first test, the <FieldInfos...> array only had a single value: ACTIVITY.
However, in this next test, the <FieldInfos...> array has multiple values: ACTIVITY and STRATEGY. So when I run the same query, it will fail because it can't return multiple values for a single column.
Query:
select
cast(substr(extractvalue(a.column_value,'/Subtype/SubtypeCode'),1,255) as number(9,0)) as subtype_code,
substr(extractvalue(a.column_value,'/Subtype/SubtypeName'),1,255) as subtype_name,
substr(extractvalue(a.column_value,'/Subtype/FieldInfos/SubtypeFieldInfo/FieldName'),1,255) as field_name,
substr(extractvalue(a.column_value,'/Subtype/FieldInfos/SubtypeFieldInfo/DomainName'),1,255) as domain_name
from
sde.gdb_items_vw
cross join
xmlsequence(xmltype(definition).extract('/DETableInfo/Subtypes/Subtype')) a
where
name = 'INFRASTR.EVENTS_MULTIPLE_ARRAY_VALUES'
Error:
ORA-19025: EXTRACTVALUE returns value of only one node
19025. 00000 - "EXTRACTVALUE returns value of only one node"
*Cause: Given XPath points to more than one node.
*Action: Rewrite the query so that exactly one node is returned.
XML:
<?xml version="1.0" encoding="UTF-8"?>
<DETableInfo xmlns:typens="http://www.esri.com/schemas/ArcGIS/10.7" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="typens:DETableInfo">
<CatalogPath>\INFRASTR.BC_EVENTS</CatalogPath>
<Name>INFRASTR.BC_EVENTS</Name>
<ChildrenExpanded>false</ChildrenExpanded>
<DatasetType>esriDTTable</DatasetType>
<DSID>60337</DSID>
<Versioned>false</Versioned>
<CanVersion>true</CanVersion>
<ConfigurationKeyword />
<RequiredGeodatabaseClientVersion>10.0</RequiredGeodatabaseClientVersion>
<HasOID>true</HasOID>
<OIDFieldName>OBJECTID</OIDFieldName>
<GPFieldInfoExs xsi:type="typens:ArrayOfGPFieldInfoEx">
<GPFieldInfoEx xsi:type="typens:GPFieldInfoEx">
<Name>OBJECTID</Name>
<AliasName>OBJECTID</AliasName>
<ModelName>OBJECTID</ModelName>
<FieldType>esriFieldTypeOID</FieldType>
<IsNullable>false</IsNullable>
<DomainFixed>true</DomainFixed>
<Required>true</Required>
<Editable>false</Editable>
</GPFieldInfoEx>
<GPFieldInfoEx xsi:type="typens:GPFieldInfoEx">
<Name>ASSET_CLASS</Name>
<AliasName>ASSET_CLASS</AliasName>
<ModelName>ASSET_CLASS</ModelName>
<FieldType>esriFieldTypeSmallInteger</FieldType>
<DefaultValueNumeric>2</DefaultValueNumeric>
<IsNullable>true</IsNullable>
</GPFieldInfoEx>
<GPFieldInfoEx xsi:type="typens:GPFieldInfoEx">
<Name>ACTIVITY</Name>
<AliasName>ACTIVITY</AliasName>
<ModelName>ACTIVITY</ModelName>
<FieldType>esriFieldTypeString</FieldType>
<IsNullable>true</IsNullable>
</GPFieldInfoEx>
<GPFieldInfoEx xsi:type="typens:GPFieldInfoEx">
<Name>STRATEGY</Name>
<AliasName>TEST_TEXT_FIELD</AliasName>
<ModelName>STRATEGY</ModelName>
<FieldType>esriFieldTypeString</FieldType>
<IsNullable>true</IsNullable>
</GPFieldInfoEx>
</GPFieldInfoExs>
<CLSID>{7A566981-C114-11D2-8A28-006097AFF44E}</CLSID>
<EXTCLSID />
<RelationshipClassNames xsi:type="typens:Names" />
<AliasName />
<ModelName />
<HasGlobalID>false</HasGlobalID>
<GlobalIDFieldName />
<RasterFieldName />
<ExtensionProperties xsi:type="typens:PropertySet">
<PropertyArray xsi:type="typens:ArrayOfPropertySetProperty" />
</ExtensionProperties>
<SubtypeFieldName>ASSET_CLASS</SubtypeFieldName>
<DefaultSubtypeCode>2</DefaultSubtypeCode>
<Subtypes xsi:type="typens:ArrayOfSubtype">
<Subtype xsi:type="typens:Subtype">
<SubtypeName>ACTIVE TRANSPORTATION</SubtypeName>
<SubtypeCode>0</SubtypeCode>
<FieldInfos xsi:type="typens:ArrayOfSubtypeFieldInfo">
<SubtypeFieldInfo xsi:type="typens:SubtypeFieldInfo">
<FieldName>ACTIVITY</FieldName>
<DomainName>ACTIVITY_ATN_1</DomainName>
</SubtypeFieldInfo>
<SubtypeFieldInfo xsi:type="typens:SubtypeFieldInfo">
<FieldName>STRATEGY</FieldName>
<DomainName>STRATEGY</DomainName>
</SubtypeFieldInfo>
</FieldInfos>
</Subtype>
<Subtype xsi:type="typens:Subtype">
<SubtypeName>GEODETIC CONTROL SURVEY MONUMENT</SubtypeName>
<SubtypeCode>1</SubtypeCode>
<FieldInfos xsi:type="typens:ArrayOfSubtypeFieldInfo">
<SubtypeFieldInfo xsi:type="typens:SubtypeFieldInfo">
<FieldName>ACTIVITY</FieldName>
<DomainName>ACTIVITY_GCSM</DomainName>
</SubtypeFieldInfo>
<SubtypeFieldInfo xsi:type="typens:SubtypeFieldInfo">
<FieldName>STRATEGY</FieldName>
<DomainName>STRATEGY</DomainName>
</SubtypeFieldInfo>
</FieldInfos>
</Subtype>
<Subtype xsi:type="typens:Subtype">
<SubtypeName>MUNICIPAL STRUCTURES (BRIDGES)</SubtypeName>
<SubtypeCode>2</SubtypeCode>
<FieldInfos xsi:type="typens:ArrayOfSubtypeFieldInfo">
<SubtypeFieldInfo xsi:type="typens:SubtypeFieldInfo">
<FieldName>ACTIVITY</FieldName>
<DomainName>ACTIVITY_MS</DomainName>
</SubtypeFieldInfo>
<SubtypeFieldInfo xsi:type="typens:SubtypeFieldInfo">
<FieldName>STRATEGY</FieldName>
<DomainName>STRATEGY</DomainName>
</SubtypeFieldInfo>
</FieldInfos>
</Subtype>
</Subtypes>
<ControllerMemberships xsi:type="typens:ArrayOfControllerMembership" />
<EditorTrackingEnabled>false</EditorTrackingEnabled>
<CreatorFieldName />
<CreatedAtFieldName />
<EditorFieldName />
<EditedAtFieldName />
<IsTimeInUTC>false</IsTimeInUTC>
<ChangeTracked>false</ChangeTracked>
<FieldFilteringEnabled>false</FieldFilteringEnabled>
<FilteredFieldNames xsi:type="typens:Names" />
</DETableInfo>
Screenshot from the application.
Question:
How can I only return a single value from the the <FieldInfos...> array: the value where FieldName = ACTIVITY?
EXTRACTVALUE is deprecated. Use XMLTABLE with the XPATH /DETableInfo/Subtypes/Subtype/FieldInfos/SubtypeFieldInfo[FieldName="ACTIVITY"] to filter to only get the ACTIVITY values and then go back up the hierarchy to get the sub-type code and name:
SELECT x.*
FROM /*sde.*/gdb_items_vw i
CROSS APPLY XMLTABLE(
'/DETableInfo/Subtypes/Subtype/FieldInfos/SubtypeFieldInfo[FieldName="ACTIVITY"]'
PASSING XMLTYPE(i.definition)
COLUMNS
SubType_Code NUMBER PATH './../../SubtypeCode',
SubType_Name VARCHAR2(255) PATH './../../SubtypeName',
Field_Name VARCHAR2(255) PATH './FieldName',
Domain_Name VARCHAR2(255) PATH './DomainName'
) x
WHERE i.name = 'INFRASTR.EVENTS_ONLY_1_ARRAY_VALUE'
Which, for the sample data, outputs:
SUBTYPE_CODE
SUBTYPE_NAME
FIELD_NAME
DOMAIN_NAME
0
ACTIVE TRANSPORTATION
ACTIVITY
ACTIVITY_ATN_1
1
GEODETIC CONTROL SURVEY MONUMENT
ACTIVITY
ACTIVITY_GCSM
2
MUNICIPAL STRUCTURES (BRIDGES)
ACTIVITY
ACTIVITY_MS
db<>fiddle here

XQuery [value()] issue for Dynamic SQL variable in Select Stateemt

I'm try to make the code below dynamic as there can be different names for the 'name' attribute in the page 'node'.
When I run the code below it returns the error 'XQuery [value()]: 'value()' requires a singleton (or empty sequence), found operand of type 'xdt:untypedAtomic *''
I feel my main issue is in the line
'C.value('(/level1/level2/template/page/#name)[sql:variable("#Counter")]','NVARCHAR(MAX)') AS [Page Name]'
where I am trying to make '#counter' variable dynamic.
Does anyone have any solutions please?
XML FOR ID 9371
<level1>
<level2>
<template width="594" height="500">
<page Cid="1" name="Test Page Name" colour="-3355393">
<image Cid="8" x="432" y="8" w="148" h="95" KeyImage="32861" Ratio="y" />
<formattedText Cid="14" x="9" y="22" w="253" h="38">
<p>
<p>
Text
</p>
</p>
</formattedText>
</page>
<page Cid="6" name="Properties">
<formattedText Cid="7" x="200" y="148" w="208" h="228">
<p>
<p>
<t>Created by </t>
<t b="b">Joe Bloggs</t>
</p>
<p />
<p>
<t>Date published 30/05/2017</t>
</p>
</formattedText>
</page>
</template>
</level2>
</level1>
RESULTS FROM SQL Query
** Present Result
Page Name | Demographics
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Test Page Name | <page Cid="1" name="Test Page Name" colour="-3355393"><image Cid="8" x="432" y="8" w="148" h="95" KeyImage="32861" Ratio="y" /><formattedText Cid="14" x="9" y="22" w="253" h="38"><p><p>Text</p></p> </formattedText></page>
Test Page Name | <page><formattedText Cid="7" x="200" y="148" w="208" h="228"><p><p> <t>Created by </t><t b="b">Joe Bloggs</t></p><p /><p><t>Date published 30/05/2017</t> </p></formattedText></page>
** Desired Result
Page Name | Demographics
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Test Page Name | <page Cid="1" name="Test Page Name" colour="-3355393"><image Cid="8" x="432" y="8" w="148" h="95" KeyImage="32861" Ratio="y" /><formattedText Cid="14" x="9" y="22" w="253" h="38"><p><p>Text</p></p> </formattedText></page>
Properties | <page><formattedText Cid="7" x="200" y="148" w="208" h="228"><p><p> <t>Created by </t><t b="b">Joe Bloggs</t></p><p /><p><t>Date published 30/05/2017</t> </p></formattedText></page>
DECLARE #TableName VARCHAR(40),
#opxml AS XML,
#hDoc AS INT,
#SQL NVARCHAR (MAX)
SELECT #opxml =
a.[filedata]
FROM [database].[dbo].[xmlfile2] a
where [Id] = 9371
DECLARE #Counter INT
DECLARE #MaxNo INT
SET #Counter=1
SET #MaxNo=(SELECT
COUNT(CAST('<page>' + CAST(C.query('./child::node()') as nvarchar(max)) + '</page>' as xml))
FROM #opxml.nodes('/level1/level2/template/page') AS T(C))
WHILE ( #Counter <= #MaxNo)
BEGIN
SELECT
C.value('(/level1/level2/template/page/#name)[sql:variable("#Counter")]','NVARCHAR(MAX)') AS
[Page Name],
CAST('<page>' + CAST(C.query('./child::node()') as nvarchar(max)) + '</page>' as xml) AS [Page_XML]
, ROW_NUMBER() OVER (ORDER BY t.c)
FROM #opxml.nodes('/level1/level2/template/page') AS T(C)
SET #Counter = #Counter + 1
END
I think
SELECT
C.value('#name','NVARCHAR(MAX)') AS [Page Name],
C.query('<page>{node()}</page>') AS [Page_XML],
ROW_NUMBER() OVER (ORDER BY t.c)
FROM #opxml.nodes('/level1/level2/template/page') AS T(C)
might suffice to produce the wanted result without the need for a WHILE loop.
I think the original problem with the long path inside of value() (e.g. C.value('(/level1/level2/template/page/#name)[sql:variable("#Counter")]','NVARCHAR(MAX)')) is due to the static type checking of XQuery in SQL server and to avoid it you basically need to add another predicate that ensures the type checker knows a single value is returned e.g. C.value('(/level1/level2/template/page/#name)[sql:variable("#Counter")][1]','NVARCHAR(MAX)')
For me, the code
DECLARE #opxml AS XML
SET #opxml = N'<level1>
<level2>
<template width="594" height="500">
<page Cid="1" name="Test Page Name" colour="-3355393">
<image Cid="8" x="432" y="8" w="148" h="95" KeyImage="32861" Ratio="y" />
<formattedText Cid="14" x="9" y="22" w="253" h="38">
<p>
<p>
Text
</p>
</p>
</formattedText>
</page>
<page Cid="6" name="Properties">
<formattedText Cid="7" x="200" y="148" w="208" h="228">
<p>
<p>
<t>Created by </t>
<t b="b">Joe Bloggs</t>
</p>
<p />
<p>
<t>Date published 30/05/2017</t>
</p>
</p>
</formattedText>
</page>
</template>
</level2>
</level1>'
SELECT
C.value('#name','NVARCHAR(MAX)') AS [Page Name],
C.query('<page>{node()}</page>') AS [Page_XML],
ROW_NUMBER() OVER (ORDER BY t.c)
FROM #opxml.nodes('/level1/level2/template/page') AS T(C)
produces the table
Page Name Page_XML (Kein Spaltenname)
Test Page Name <page><image Cid="8" x="432" y="8" w="148" h="95" KeyImage="32861" Ratio="y" /><formattedText Cid="14" x="9" y="22" w="253" h="38"><p><p>
Text
</p></p></formattedText></page> 1
Properties <page><formattedText Cid="7" x="200" y="148" w="208" h="228"><p><p><t>Created by </t><t b="b">Joe Bloggs</t></p><p /><p><t>Date published 30/05/2017</t></p></p></formattedText></page> 2
so at least the Page_Name seems to be easily populated by using e.g. C.value('#name','NVARCHAR(MAX)') AS [Page Name]

ISO 8583 message numeric in byte

Config:
<template type="0200">
<field num="3" type="NUMERIC" length="6">000000</field>
<field num="11" type="NUMERIC" length="6" />
<field num="24" type="NUMERIC" length="3" />
</template>
Code:
mfact.setTraceNumberGenerator(new SimpleTraceGenerator((int) (System
.currentTimeMillis() % 100000)));
m = mfact.newMessage(0x200);
m.setBinary(false);
m.setValue(24, 109, IsoType.NUMERIC, 3);
String strMsg = new String(msg.writeData());
I get the following result for strMsg
05002020010000000000920000058121109
Please look at the last 3 number.
The result should be:
050020200100000000009200000581210109
Why is the field 24 is 109, I thought it should be 0109?

How can I get unique branch of xmltype as varchar?

Oracle 11g2.
For example:
select XMLType(
'<main>
<article>
<title>1.txt</title>
<type>market</type>
<author>
<name>J. Smith</name>
<age>32</age>
</author>
</article>
<comment>For information</comment>
</main>').getStringVal() from dual;
Could you help me modify this select statement ?
I'd like to get varchar output as :
<title>1.txt</title>
<type>market</type>
<author>
<name>J. Smith</name>
<age>32</age>
</author>
unfortunately, using extract('/main/article') as:
select XMLType(
'<main>
<article>
<title>1.txt</title>
<type>market</type>
<author>
<name>J. Smith</name>
<age>32</age>
</author>
</article>
<comment>For information</comment>
</main>').extract('/main/article').getStringVal() from dual;
lose format of the text (all output in one row).
Thank you in advance.
You can do this (well, including the article node) via XMLTABLE and XMLSERIALISE to do the pretty printing, e.g.:
Query
with sample_data as (select XMLType(
'<main>
<article>
<title>1.txt</title>
<type>market</type>
<author>
<name>J. Smith</name>
<age>32</age>
</author>
</article>
<comment>For information</comment>
</main>') xdata from dual)
select xmlserialize(document x.col1 as varchar2(4000) indent size = 2)
from sample_data sd
cross join xmltable('/main/article'
passing sd.xdata
columns col1 xmltype path '.') x;
Result
<article>
<title>1.txt</title>
<type>market</type>
<author>
<name>J. Smith</name>
<age>32</age>
</author>
</article>
As #Boneist shows you can use xmlserialize() for the formatting, but as you only seem to have a single article node in your document you can still use your extract():
select xmlserialize(document XMLType(
'<main>
<article>
<title>1.txt</title>
<type>market</type>
<author>
<name>J. Smith</name>
<age>32</age>
</author>
</article>
<comment>For information</comment>
</main>').extract('/main/article')
as varchar2(200) indent) as article
from dual;
Or you can use an XMLQuery:
select xmlserialize(document xmlquery('/main/article'
passing XMLType(
'<main>
<article>
<title>1.txt</title>
<type>market</type>
<author>
<name>J. Smith</name>
<age>32</age>
</author>
</article>
<comment>For information</comment>
</main>')
returning content)
as varchar2(200) indent) as article
from dual;
ARTICLE
--------------------------------------------------------------------------------
<article>
<title>1.txt</title>
<type>market</type>
<author>
<name>J. Smith</name>
<age>32</age>
</author>
</article>

strange behavior of SQL Server when sum nodes's values in XML

I ask a question about sum node's values:
sum some xml nodes values in sql server 2008
Please consider this code:
Declare #xml xml
set #xml='<Parent ID="p">
<Child ID="1">1000000000</Child >
<Child ID="2">234650</Child >
<Child ID="3">0</Child >
</Parent >'
Select #xml.value('sum(/Parent[#ID="p"]/Child)','bigint') as Sum
if you execute this it retrun this error:
Msg 8114, Level 16, State 5, Line 8
Error converting data type nvarchar to bigint.
the problem is it return this value : 1.00023465E9
if I change the above query this way it being ok:
Declare #xml xml
set #xml='<Parent ID="p">
<Child ID="1">1000000000</Child >
<Child ID="2">234650</Child >
<Child ID="3">0</Child >
</Parent >'
Select #xml.value('sum(/Parent[#ID="p"]/Child)','float') as Sum
Why Sql Server do this?
Sql Server has a problem converting the value with scientific notation from a string to an integer, as would happen when you run your xpath query, however, it can do this for float.
You could write your query like this:
select #xml.value('sum(/Parent[#ID = "p"]/Child) cast as xs:long?', 'bigint')
Try this one -
DECLARE #xml XML
SELECT #xml='<Parent ID="p">
<Child ID="1">1000000000</Child >
<Child ID="2">234650</Child >
<Child ID="3">0</Child >
</Parent >'
SELECT #xml.value('sum(for $r in /Parent[#ID="p"]/Child return xs:int($r))', 'bigint')
UPDATE:
DECLARE #xml XML
SELECT #xml='<Parent ID="p">
<Child ID="1">100000000000000</Child >
<Child ID="2">234650</Child >
<Child ID="3">0</Child >
</Parent >'
SELECT #xml.value('sum(for $r in /Parent[#ID="p"]/Child return xs:decimal($r))', 'bigint')
UPDATE 2:
DECLARE #xml XML
SELECT #xml='<Parent ID="p">
<Child ID="1">100000000000000.6</Child >
<Child ID="2">234650</Child >
<Child ID="3">0</Child >
</Parent >'
SELECT #xml.value('sum(for $r in /Parent[#ID="p"]/Child return xs:decimal($r))', 'decimal(18,2)')
Try this is working with BIGINT:
DECLARE #SearchKeyWords XML
SET #SearchKeyWords =
'<Parent ID=''p''>
<Child ID="1">1000000000</Child >
<Child ID="2">234650</Child >
<Child ID="3">0</Child >
</Parent >'
DECLARE #TempSearchKeyWords TABLE
(
SearchKeyWord BIGINT
)
INSERT INTO #TempSearchKeyWords
SELECT SearchKeyWords.SearchKeyword.value('.',' bigint ') AS SearchKeyword
FROM #SearchKeyWords.nodes('/Parent/Child') AS SearchKeyWords(SearchKeyword)
SELECT SUM(SearchKeyWord) FROM #TempSearchKeyWords
The XML you have here is untyped XML. That means the values provided to sum() is of type xdt:untypedAtomic. When sum() is used on xdt:untypedAtomic the values are cast to xs:double. The result of sum() is read by the values() function as a string (or untypedAtomic) and xs:double uses the scientific notation when the value is less than 1.0E-6, or greater than or equal to 1.0E6. SQL Server can not convert from scientific notation to int or bigint.
Ref:
sum Function (XQuery)
Type Casting Rules in XQuery
Other answers have provided workarounds that cast the input values or the result from sum() or using float as the data type in values(). Another option could be to use typed XML instead.
Schema:
create xml schema collection XSDSumTest as '
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="Parent">
<xs:complexType>
<xs:sequence>
<xs:element name="Child" maxOccurs="unbounded">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:int">
<xs:attribute name="ID" type="xs:int"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="ID" type="xs:string"/>
</xs:complexType>
</xs:element>
</xs:schema>'
Query:
declare #xml xml(XSDSumTest) = '
<Parent ID="p">
<Child ID="1">1000000000</Child >
<Child ID="2">234650</Child >
<Child ID="3">0</Child >
</Parent>'
select #xml.value('sum(/Parent[#ID="p"]/Child)','bigint') as Sum