I have a hierarchical data whose structure is subject to change. The relationships are maintained in a single table that are identified by self referencing on two columns, the node ID and a Parent ID. I would like to be able run a query to pivot the data so that each row represents the lowest unit of the nodes.
For example:
If I have a table that looks like this...
I would like to be able to get to this...
I've played around with doing several joins as an attempt to get everything on the same line...
SELECT L1.NAME AS CITY, L2.NAME AS COUNTY, L3.NAME AS STATE, L4.NAME AS
COUNTRY
FROM TABLENAME L1
LEFT JOIN TABLENAME AS L2 ON L1.PARENT_NODE_ID = L2.NODE_ID
LEFT JOIN TABLENAME AS L3 ON L2.PARENT_NODE_ID = L3.NODE_ID
LEFT JOIN TABLENAME AS L4 ON L3.PARENT_NODE_ID = L4.NODE_ID
WHERE L1.Type = City
Here is the heart of the question: I may not always know the structure of the hierarchy. Thus I need a solution that could handle changes. Say the keepers of the business logic decide that we need to add Hemisphere above country. Or a Region (West Coast, Central, East Coast) above State. City however will always be the lowest node. I need something that can exist independent of the hierarchical structure.
UPDATE My original question I used a simple example. In my actual solution I must leverage several joins to get the hierarchy that I need. I am working on the bellow query but as of now it returns null for every column that I wish to populate. Most likely an issue with the case statements?
;WITH ALLORGS AS( --All Orgs
SELECT ORGS.ID, ORGS.ORG_NAME
, HIER.ID_PARENTORG, TYP.ORG_TYPE_DESCR
FROM ORGANIATIONS AS ORGS
FULL OUTER JOIN HIERARCHYTABLE AS HIER ON ORGS.ID = HIER.ID_ORG
FULL OUTER JOIN ORGANIZATION_TYPES AS TYP ON ORGS.ID_ORG_TYPE = TYP.ID
), CTE AS (
SELECT ID
, ID_PARENTORG
, L1.ORG_NAME
--, ORG_TYPE_DESCR
, CAST('' as varchar(100)) AS UNIT
, CAST('' as varchar(100)) AS REGION
, CAST('' as varchar(100)) AS DDA_POOL
, CAST('' as varchar(100)) AS COUNTY
, CAST('' as varchar(100)) AS STATE
, CAST('' as varchar(100)) AS BUSINESS_UNIT
, CAST('' as varchar(100)) AS PROEPRTY
, CAST('' as varchar(100)) AS DISTRICT
, 1 AS FLAG
FROM ALLORGS L1
WHERE L1.ORG_TYPE_DESCR = 'COST CENTER'
UNION ALL
SELECT T1.ID
,L2.ID_PARENTORG
,T1.ORG_NAME AS COSTCNTR
--, T.ORG_TYPE_DESCR
,CASE WHEN L2.ORG_TYPE_DESCR = 'UNIT' THEN L2.ORG_NAME ELSE NULL END AS UNIT
,CASE WHEN L2.ORG_TYPE_DESCR = 'REGION' THEN L2.ORG_NAME ELSE NULL END AS REGION
,CASE WHEN L2.ORG_TYPE_DESCR = 'DDA_POOL' THEN L2.ORG_NAME ELSE NULL END AS DDA_POOL
,CASE WHEN L2.ORG_TYPE_DESCR = 'COUNTRY' THEN L2.ORG_NAME ELSE NULL END AS COUNTRY
,CASE WHEN L2.ORG_TYPE_DESCR = 'STATE' THEN L2.ORG_NAME ELSE NULL END AS STATE
,CASE WHEN L2.ORG_TYPE_DESCR = 'BUSINESS_UNIT' THEN L2.ORG_NAME ELSE NULL END AS BUSINESS_UNIT
,CASE WHEN L2.ORG_TYPE_DESCR = 'PROPERTY' THEN L2.ORG_NAME ELSE NULL END AS PROPERTY
,CASE WHEN L2.ORG_TYPE_DESCR = 'DISTRICT' THEN L2.ORG_NAME ELSE NULL END AS DISTRICT
,T1.FLAG + 1 AS FLAG
FROM CTE AS T1
INNER JOIN ALLORGS AS L2 ON T1.ID_PARENTORG = L2.ID
)
SELECT a.ID
,a.ORG_NAME AS COSTCNTR
,UNIT
,REGION
,DDA_POOL
,COUNTY
,STATE
,BUSINESS_UNIT
,PROEPRTY
,DISTRICT
FROM CTE AS a
INNER JOIN (SELECT ID, MAX(FLAG) FLAG FROM CTE GROUP BY ID) b ON a.ID = b.ID AND a.FLAG = b.FLAG