Who am I and why should you read this blog?

I've been working with Business Intelligence software in one form or another for the past 10 years. Beyond my BI experience, I have a finance background ranging over 17 years. Primarily in recent years I've focused on working with the Oracle/Hyperion Essbase OLAP product. Over the years I've been an end user, administrator, developer, consultant, and most recently I am a Vice President for Financial Systems Development at a large financial brokerage firm. I was certified on Essbase in 2004 and received an Oracle Ace award in 2008. I can honestly say I've gotten a lot out of working in this field and I like to give back as much as I can. I've always been very active in user forums and I thought I could be of more service to my fellow developers (presumably by sharing my ideas) if I started a blog to share some of my experiences. Beyond Essbase and its related products I am also a heavy relational database user/developer and ETL developer. So you can expect to find more on this blog than just Essbase. I love the idea of manipulating data and turning it into something useful and when I can, I'll share with you how I do it.
Beyond the technical talk, I find BI to be an architecture for management and when applicable I'll also be talking about the human side (some say the ugly side) of Business Intelligence. I hope you enjoy and can make use of the content you find here.

Best Regards,

Gary Crisci

Thursday, February 17, 2011

SQL queries for Essbase developers

So when I first set up this blog I posted that I would not only write about Essbase all of the time and I would include other content as well. Looking back over my posts, I have not lived up to that too well, so here's one in the "other technology" category. Of course it still has an Essbase slant on it, but even if you are one of those non-believers that uses a different OLAP technology, some of these examples might still be of interest to you.

Recursive (Parent/Child) queries in SQL.
Let's say you are well organized and have your metadata structures in relational tables, rather than just living in some Excel files. Now suppose you want to spin off a cube from one of these structures, but you don't want the entire structure, maybe you just want a particular branch of the hierarchy (i.e. all descendants below a certain parent). Pulling that kind of query in a relational database used to be kind of tough. Here's an example of how to do it.

Let's say you start off with an Outline extract of the Sample Basic database for the Market dimension and you want to query the table to get all descendant of "East".


WITH Descendants (child,parent) AS
(SELECT [CHILD0,Market], [PARENT0,Market]
FROM dbo.Market
WHERE [PARENT0,Market] = 'East'
UNION ALL
SELECT dbo.Market.[CHILD0,Market],
dbo.Market.[PARENT0,Market]
FROM dbo.Market
INNER JOIN Descendants ON dbo.Market.[PARENT0,Market]= Descendants.child)

SELECT DISTINCT dbo.Market.[PARENT0,Market], dbo.Market.[CHILD0,Market]
FROM dbo.Market
INNER JOIN Descendants ON dbo.Market.[CHILD0,Market] = Descendants.child




Your results will be


PARENT0,Market CHILD0,Market
East Connecticut
East Florida
East Massachusetts
East New Hampshire
East New York



Play around with it and see what you can do with it.
Be forewarned, if the table is big this might take a while.
Also note that this "Descendants" feature in MS SQL Server didn't show up until SQL Server 2005.


Another one I have heard is how do I take a parent/child table and turn it into Generations or Levels.

Using a basic Parent/Child table going to Generations would look like this


SELECT a_1.Parent AS Gen1, b_1.Child AS Gen2, c_1.Child AS Gen3, d_1.Child AS Gen4, e_1.Child AS Gen5
FROM (SELECT Parent
FROM dbo.Test_table
WHERE (Parent NOT IN
(SELECT DISTINCT Child
FROM dbo.Test_table AS A))) AS a_1 INNER JOIN
(SELECT DISTINCT Child, Parent
FROM dbo.Test_table AS B) AS b_1 ON a_1.Parent = b_1.Parent LEFT OUTER JOIN
(SELECT DISTINCT Child, Parent
FROM dbo.Test_table AS C) AS c_1 LEFT OUTER JOIN
(SELECT DISTINCT Child, Parent
FROM dbo.Test_table AS D) AS d_1 LEFT OUTER JOIN
(SELECT DISTINCT Child, Parent
FROM dbo.Test_table AS E) AS e_1 ON d_1.Child = e_1.Parent ON c_1.Child = d_1.Parent ON b_1.Child = c_1.Parent
GROUP BY a_1.Parent, b_1.Child, c_1.Child, d_1.Child, e_1.Child



If you want to go to levels it would look like this.


SELECT a_1.Child AS lev0, b_1.Parent AS lev1, c_1.Parent AS lev2,
d_1.Parent AS lev3, e_1.Parent AS lev4
FROM (
SELECT Child
FROM dbo.Test_table
WHERE(Child NOT IN
(SELECT DISTINCT Parent
FROM dbo.Test_table AS A))) AS a_1 INNER JOIN
(SELECT DISTINCT Child, Parent
FROM dbo.Test_table AS B) AS b_1 ON a_1.Child = b_1.Child LEFT OUTER JOIN
(SELECT DISTINCT Child, Parent
FROM dbo.Test_table AS C) AS c_1 LEFT OUTER JOIN
(SELECT DISTINCT Child, Parent
FROM dbo.Test_table AS D) AS d_1 LEFT OUTER JOIN
(SELECT DISTINCT Child, Parent
FROM dbo.Test_table AS E) AS e_1 ON d_1.Parent = e_1.Child ON
c_1.Parent = d_1.Child ON b_1.Parent = c_1.Child



Lastly, let's say you have Generations and you want to go to Parent/Child.
It is important to have a sort key on your source table to maintain the proper order.

So assume the source table looks like

Sort_ID, Gen1, Gen2, Gen3, Gen4

You would create a target table then run some insert queries to cycle through the source table. Lastly I like to run a couple of update queries to tag lev0 members and upper level members.


CREATE TABLE [dbo].[Target] (
[ID] [decimal](18, 0) IDENTITY (1, 1) NOT NULL ,
[parent] [varchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,
[member] [varchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
[group_item_flag] [varchar] (1) COLLATE SQL_Latin1_General_CP1_CI_AS NULL
) ON [PRIMARY]


INSERT INTO [dbo].[Target] ([parent], [member])
SELECT [Gen1], [Gen2]
FROM [dbo].[Source]
GROUP BY [Gen1], [Gen2]
HAVING (NOT ([Gen2] IS NULL))
ORDER BY MIN([sort_key])

INSERT INTO [dbo].[Target] ([parent], [member])
SELECT [Gen2], [Gen3]
FROM [dbo.[Source]
GROUP BY [Gen2], [Gen3]
HAVING (NOT ([Gen3] IS NULL))
ORDER BY MIN([sort_key])

INSERT INTO [dbo].[Target] ([parent], [member])
SELECT [Gen3], [Gen4]
FROM [dbo.[Source]
GROUP BY [Gen1], [Gen2]
HAVING (NOT ([Gen2] IS NULL))
ORDER BY MIN([sort_key])

UPDATE [dbo].[Target]
SET [group_item_flag] = 'G'
WHERE [member] IN (
SELECT DISTINCT [parent]
FROM [dbo].[Target])

UPDATE [dbo].[Target]
SET [group_item_flag] = 'I'
WHERE [member] NOT IN (
SELECT DISTINCT [parent]
FROM [dbo].[Target])



Let me know some of your favorites in the comments.

2 comments:

christi parks said...

Hello all,I am new and I would like to ask that what are the benefits of sql training, what all topics should be covered and it is kinda bothering me ... and has anyone studies from this course wiziq.com/course/125-comprehensive-introduction-to-sql of SQL tutorial online?? or tell me any other guidance...
would really appreciate help... and Also i would like to thank for all the information you are providing on sql.

Oracle SQL said...

I lately came across your weblog and have been learning along. I believed I would leave my 1st comment. I do not know what to say except that I've loved reading. Fine blog. I will keep visiting this weblog incredibly normally.