How can I configure dimension to ignore specific value - mdx

I have an existing fact table and I need to modeling an OLAP cube using Mondrian Schema.
Fact table has several columns with the primary key of dimension table but unluckily there are row with dimension value "0" with the convention of "all"
Example with only one dimension: student_id:
| student_id | exams
+------------+-------------
| 0 | 23
| 20131 | 15
| 20168 | 2
| 20468 | 6
student table
id | name
-------+-----------
20131 | John
20168 | Daid
20468 | Peter
20629 | Paul
22344 | Micheal
My schema is:
<Schema name="students">
<Dimension type="StandardDimension" visible="true" name="StudentDimension">
<Hierarchy name="Student" visible="true" hasAll="true" primaryKey="id">
<Table name="student" schema="public" alias="" />
<Level name="Nome" visible="true" column="name" type="String" uniqueMembers="false" levelType="Regular" />
</Hierarchy>
</Dimension>
<Cube name="studentCube" visible="true" cache="true" enabled="true">
<Table name="students_cube" schema="public" />
<DimensionUsage source="StudentDimension" name="StudentUsage" visible="true" foreignKey="student_id" />
<Measure name="Exams" column="exams" datatype="Numeric" aggregator="sum" visible="true" />
</Cube>
</Schema>
My problem is that executing the query:
SELECT
{[Measures].[Exams]} ON COLUMNS,
{[StudentUsage.Student].[All StudentUsage.Student]} ON ROWS
FROM [studentCube]
I have the result "46": the sum of all the exams included the row with student_id = 0.
I'd like to exclude in the schema the measures associated to dimensions with value "0". Is it possible?

You could try this:
SELECT
{[Measures].[Exams]} ON COLUMNS,
{
[StudentUsage.Student].[All StudentUsage.Student] -
[StudentUsage.Student].[All StudentUsage.Student].&[0]
} ON ROWS
FROM [studentCube]
Or try:
SELECT
{[Measures].[Exams]} ON COLUMNS,
EXCEPT
(
[StudentUsage.Student].[All StudentUsage.Student] ,
[StudentUsage.Student].[All StudentUsage.Student].&[0]
) ON ROWS
FROM [studentCube]

Related

How to extract multiple tag values from XML column in SQL Server

I would like to know how to extract multiple values from a single XML row, the problem is that this XML value somethimes have duplicate (name, id, email) tag childs,
for example:
<foo>
<name>
Dacely Lara Camilo
</name>
<id>
001-1942098-2
</id>
<email>
myuncletouchme#gmail.com
</email>
</foo>
<foo>
<name>
Alba Elvira Castro
</name>
<id>
001-0327959-2
</id>
<email>
4doorsmorehorse#hotmail.com
</email>
</foo>
Or somethimes the data in that column can be like this
<foo>
<name>
Nelson Antonio Jimenez
</name>
<id>
001-0329459-3
</id>
<email>
gsucastillo#tem.com
</email>
</foo>
<foo>
<name>
Emelinda Serrano
</name>
<id>
001-0261732-4
</id>
<email>
gucastillo#tem.com
</email>
</foo>
<foo>
<name>
Nelson Antonio Jimenez
</name>
<id>
001-0329259-3
</id>
<email>
gucastillo#tem.com
</email>
</foo>
<foo>
<name>
Emelinda Serrano
</name>
<id>
001-0268332-4
</id>
<email>
gucastillo#tem.com
</email>
</foo>
And I want all of then to be transpose to a single row just like this:
My current code just extract the first pair, if it can help,
WITH BASEDATA (ID, SIGNATURE, X) AS (
SELECT TOP 50
A.ID_SIGNATURE,
A.SIGNATURE,
A.XML
FROM DWH.DIM_CORE_SIGNATURE A
)SELECT
ID,
A.value('(id)[1]', 'nvarchar(max)') AS ID_SIGNATURE,
A.value('(name)[1]', 'nvarchar(max)') AS NAME,
A.value('(email)[1]', 'nvarchar(max)') AS EMAIL
FROM BASEDATA
CROSS APPLY X.nodes('//foo') AS SIGNATURE(A)
Notable points:
.nodes('/foo') method has a better, more performant XPath expression.
It is better to use .value('(id/text())[1]',... for the same
reason.
As #Lamu already suggested, it is better to use real data types instead of nvarchar(max) across the board.
SQL
-- DDL and sample data population, start
DECLARE #tbl TABLE (ID INT IDENTITY PRIMARY KEY, xmldata XML);
INSERT INTO #tbl (xmldata) VALUES
(N'<foo>
<name>Dacely Lara Camilo</name>
<id>001-1942098-2</id>
<email>myuncletouchme#gmail.com</email>
</foo>
<foo>
<name>Alba Elvira Castro</name>
<id>001-0327959-2</id>
<email>4doorsmorehorse#hotmail.com</email>
</foo>')
, (N'<foo>
<name>Nelson Antonio Jimenez</name>
<id>001-0329459-3</id>
<email>gsucastillo#tem.com</email>
</foo>
<foo>
<name>Emelinda Serrano</name>
<id>001-0261732-4</id>
<email>gucastillo#tem.com</email>
</foo>
<foo>
<name>Nelson Antonio Jimenez</name>
<id>001-0329259-3</id>
<email>gucastillo#tem.com</email>
</foo>
<foo>
<name>Emelinda Serrano</name>
<id>001-0268332-4</id>
<email>gucastillo#tem.com</email>
</foo>');
-- DDL and sample data population, end
SELECT ID,
c.value('(id/text())[1]', 'char(13)') AS ID_SIGNATURE,
c.value('(name/text())[1]', 'nvarchar(30)') AS NAME,
c.value('(email/text())[1]', 'nvarchar(128)') AS EMAIL
FROM #tbl
CROSS APPLY xmldata.nodes('/foo') AS t(c);
Output
+----+---------------+----------------------+-----------------------------+
| ID | ID_SIGNATURE | NAME | EMAIL |
+----+---------------+----------------------+-----------------------------+
| 1 | 001-1942098-2 | Dacely Lara Camilo | myuncletouchme#gmail.com |
| 1 | 001-0327959-2 | Alba Elvira Castro | 4doorsmorehorse#hotmail.com |
| 2 | 001-0329459-3 | Nelson Antonio Jimen | gsucastillo#tem.com |
| 2 | 001-0261732-4 | Emelinda Serrano | gucastillo#tem.com |
| 2 | 001-0329259-3 | Nelson Antonio Jimen | gucastillo#tem.com |
| 2 | 001-0268332-4 | Emelinda Serrano | gucastillo#tem.com |
+----+---------------+----------------------+-----------------------------+

How to extract data in tabular format from XML field in Oracle database?

I'm trying to extract data in tabular format from an XML field in an Oracle database.
Please see sample xml field below:
<?xml version='1.0' encoding='UTF-8'?>
<root>
<element1>
<Header Client_ID="100" Sent_date_time="2015-03-02T9:30:43.808-06:00"/>
<element2>
<element3 UnitPrice="3.2" ItemID="njh1"/>
<element3 UnitPrice="4.1" ItemID="ole5"/>
<element3 UnitPrice="4.6" ItemID="usd3"/>
<element3 UnitPrice="8.2" ItemID="eor9"/>
<element3 UnitPrice="2.9" ItemID="abc8"/>
<element3 UnitPrice="5.1" ItemID="gfd3"/>
<element3 UnitPrice="4.9" ItemID="kdu0"/>
<element3 UnitPrice="6.1" ItemID="uso8"/>
</element2>
</element1>
</root>
My aim is to query the itemID and UnitPrice fields from the xml field above in the format shown below:
ItemID UnitPrice
njh1 3.2
ole5 4.1
usd3 4.6
eor9 8.2
abc8 2.9
gfd3 5.1
kdu0 4.9
uso8 6.1
I'm fairly new to querying data from xml fields. I have tried using the getStringVal, but all I get is one single long string.
Please advise on a solution. Please note that I don't have dba rights to this database.
Thank you
You have to use XMLTABLE function for this.
SQL Fiddle
Oracle 11g R2 Schema Setup:
create table xml_test(
xml_col varchar2(2000)
);
insert into xml_test values(
'<?xml version=''1.0'' encoding=''UTF-8''?>
<root>
<element1>
<Header Client_ID="100" Sent_date_time="2015-03-02T9:30:43.808-06:00"/>
<element2>
<element3 UnitPrice="3.2" ItemID="njh1"/>
<element3 UnitPrice="4.1" ItemID="ole5"/>
<element3 UnitPrice="4.6" ItemID="usd3"/>
<element3 UnitPrice="8.2" ItemID="eor9"/>
<element3 UnitPrice="2.9" ItemID="abc8"/>
<element3 UnitPrice="5.1" ItemID="gfd3"/>
<element3 UnitPrice="4.9" ItemID="kdu0"/>
<element3 UnitPrice="6.1" ItemID="uso8"/>
</element2>
</element1>
</root>'
);
Query:
select cols.ItemID, cols.UnitPrice
from xml_test x,
xmltable('root/element1/element2/element3'
passing xmltype(x.xml_col)
columns ItemID varchar2(10) path '#ItemID',
UnitPrice varchar2(10) path '#UnitPrice'
) cols;
Results:
| ITEMID | UNITPRICE |
|--------|-----------|
| njh1 | 3.2 |
| ole5 | 4.1 |
| usd3 | 4.6 |
| eor9 | 8.2 |
| abc8 | 2.9 |
| gfd3 | 5.1 |
| kdu0 | 4.9 |
| uso8 | 6.1 |

Coldfusion Calculate Sum Total (Loop? )

ok. so i have this table:
|item| quantity| price|
|apple | 2 | 2.00 |
|orange | 3 | 1.50 |
|grape | 5 | 2.50 |
i want to display the Grand Total that a customer has to pay.
how to do that? enter code here
i don't really know how to use array. can anyone show me how?
my code (sort of)
the price is shown in each of the row using this query:
<cfquery name="getPrice" datasource="fruits">
select *
from fruits
</cfquery>
<cfloop query="getPrice">
#quantity# | #price# | #totalPrice#
</cfloop><br>
the Grand Total should be displayed in the last row (Grand Total =$ 21.00 ).
Thanks for your help.
<cfset grandTotal = 0 />
<cfloop query="getPrice">
#quantity# | #price# | #totalPrice#<br />
<cfset grandTotal = grandTotal + ( price * quantity ) />
</cfloop>
<br /><br />
<cfoutput>#grandTotal#</cfoutput>
If ALL you want is the grand total, you can do that in SQL without looping over the records as:
<cfquery name="getPrice" datasource="fruits">
select sum(price*quantity) as grandTotal
from fruits
</cfquery>
Total: <cfoutput>#getPrice.grandTotal#</cfoutput>

xQuery and T-SQL to Extract Data

Got some basic XML as a XML datatype within SQL 2005. One record/row looks like this
<doc>
<level1>
<level2>
<name>James</name>
<age>12</age>
</level2>
<level2>
<name>John</name>
<age>23</age>
</level2>
</level1>
</doc>
When I perform some basic T_SQL
SELECT TOP 1
DocumentXML.query('data(//doc/name)'),
DocumentXML.query('data(//doc/age)')
FROM [DBNAME].[dbo].[TBLNAME]
I get
ID | Name | Age
----------------------
1 | JamesJohn | 1223
How do I re-write the T-SQL so it displays as
ID | Name | Age
--------------------
1 | James | 12
2 | John | 23
Your example doesn't work for me; the second level2 opens with </level2>. And //doc/name doesn't exist; might be //doc/level1/level2/name.
Here's an example of how to retrieve a rowset from an XML:
declare #t table (id int identity, doc xml)
insert #t (doc) values (
'<doc>
<level1>
<level2>
<name>James</name>
<age>12</age>
</level2>
<level2>
<name>John</name>
<age>23</age>
</level2>
</level1>
</doc>')
SELECT x.a.value('(name)[1]','varchar(50)') as col1
, x.a.value('(age)[1]','varchar(50)') as col2
FROM #t t
cross apply
t.doc.nodes('//level2') x(a)
This prints:
col1 col2
James 12
John 23

SQL Server 2005 "FOR XML PATH" Grouping

I'm trying to generate a XML document from the SQL Server 2005 database by using "FOR XML" construct.
There are two simple tables in the database with a one-to-many relationship:
1) Magazines
| Id | Number | Name |
----------------------------
| 53 | 0001 | Magazine 1 |
| 54 | 0002 | Magazine 2 |
| 55 | 0003 | Magazine 3 |
2) Articles
| Id | Title | MagazineId | Size |
--------------------------------------
| 1 | Article 1 | 53 | 1205 |
| 2 | Article 2 | 53 | 817 |
| 3 | Article 3 | 54 | 1570 |
| 4 | Article 4 | 54 | 2510 |
| 5 | Article 5 | 55 | 910 |
Let's assume I have to find all magazines that have an article with size greater than 1000
and to produce the following xml:
<Magazines>
<Magazine Id="53">
<Number>0001</Number>
<Articles>
<Article Id="1">
<Title>Article 1</Title>
<Size>1205</Size>
</Article>
</Articles>
</Magazine>
<Magazine Id="54">
<Number>0002</Number>
<Articles>
<Article Id="3">
<Title>Article 3</Title>
<Size>1570</Size>
</Article>
<Article Id="4">
<Title>Article 4</Title>
<Size>2510</Size>
</Article>
</Articles>
</Magazine>
</Magazines>
I'm trying to produce such xml by using a "PATH" mode:
SELECT Magazines.Id AS "#Id",
Magazines.Number AS "Number",
Articles.Id AS "Articles/Article/#Id",
Articles.Title AS "Articles/Article/Title",
Articles.Size AS "Articles/Article/Size"
FROM Magazines INNER JOIN Articles ON Magazines.Id = Articles.MagazineId
WHERE Articles.Size > 1000
FOR XML PATH('Magazine'), ROOT('Magazines'), TYPE
It will produce the following xml:
<Magazines>
<Magazine Id="53">
<Number>0001</Number>
<Articles>
<Article Id="1">
<Title>Article 1</Title>
<Size>1205</Size>
</Article>
</Articles>
</Magazine>
<Magazine Id="54">
<Number>0002</Number>
<Articles>
<Article Id="3">
<Title>Article 3</Title>
<Size>1570</Size>
</Article>
</Articles>
</Magazine>
<Magazine Id="54">
<Number>0002</Number>
<Articles>
<Article Id="4">
<Title>Article 4</Title>
<Size>2510</Size>
</Article>
</Articles>
</Magazine>
</Magazines>
So there are two elements for the Magazine with Id="54" (one for each article) and this is the problem.
I can rewrite the query using a subquery like this:
SELECT M.Id AS "#Id",
M.Number AS "Number",
(SELECT Articles.Id AS "#Id",
Articles.Title AS "Title",
Articles.Size AS "Size"
FROM Articles
WHERE Articles.MagazineId = M.Id
FOR XML PATH('Article'), ROOT('Articles'), TYPE
)
FROM Magazines AS M
FOR XML PATH('Magazine'), ROOT('Magazines'), TYPE
And this produce the following xml:
<Magazines>
<Magazine Id="53">
<Number>0001</Number>
<Articles>
<Article Id="1">
<Title>Article 1</Title>
<Size>1205</Size>
</Article>
<Article Id="2">
<Title>Article 2</Title>
<Size>817</Size>
</Article>
</Articles>
</Magazine>
<Magazine Id="54">
<Number>0002</Number>
<Articles>
<Article Id="3">
<Title>Article 3</Title>
<Size>1570</Size>
</Article>
<Article Id="4">
<Title>Article 4</Title>
<Size>2510</Size>
</Article>
</Articles>
</Magazine>
<Magazine Id="55">
<Number>0003</Number>
<Articles>
<Article Id="5">
<Title>Article 5</Title>
<Size>910</Size>
</Article>
</Articles>
</Magazine>
</Magazines>
But by using a subquery I can not filter magazines by articles columns (without complex additional queries).
The "FOR XML AUTO" mode is not suitable, because it is very simple and does not support some "PATH" features (like attributes using #, ROOT, etc..)
So, Is there any possibility in "PATH" mode to group inner table data like in "AUTO" mode?
Thank you!
Well, you can get one step closer by specifying the "size > 1000" inside your subquery:
SELECT M.Id AS "#Id",
M.Number AS "Number",
(SELECT Articles.Id AS "#Id",
Articles.Title AS "Title",
Articles.Size AS "Size"
FROM Articles
WHERE Articles.MagazineId = M.Id
AND Articles.Size > 1000
FOR XML PATH('Article'), ROOT('Articles'), TYPE
)
FROM Magazines AS M
FOR XML PATH('Magazine'), ROOT('Magazines'), TYPE
What you're missing now is the fact you'll still get magazines that have no articles with a size > 1000. You can eliminate those something like this:
SELECT M.Id AS "#Id",
M.Number AS "Number",
(SELECT Articles.Id AS "#Id",
Articles.Title AS "Title",
Articles.Size AS "Size"
FROM Articles
WHERE Articles.MagazineId = M.Id
AND Articles.Size > 1000
FOR XML PATH('Article'), ROOT('Articles'), TYPE
)
FROM Magazines AS M
WHERE EXISTS(SELECT * FROM Articles
WHERE Articles.MagazineId = M.Id
AND Articles.Size > 1000)
FOR XML PATH('Magazine'), ROOT('Magazines'), TYPE
(untested, I don't have a SQL server at hand right now).
Does that work for you? Does it give you the magazines and articles you're looking for?
Marc
Use FOR XML explicit. Is longest code to write but disappear the performance issues provocate by sub queries.