SQL PIVOT QUERY ISSUE - sql-server-2008

I have a table [dbo].[RISK_DISCPLN]
RISK_DISCPLN_ID RISK_DISCPLN_NM
1 LegalRisk
2 institutional Risk
4 Market Risk
Tabbe Name [dbo].[PROJ_RISK_DISCPLN]
PROJ_ID RISK_DISCPLN_ID
1 1
1 2
1 4
2 1
2 2
2 4
3 1
3 2
3 4
Table Name [dbo].[USER]
USER_ID USER_FIRST_NM USER_LST_NM
2 saravanakumar rajkumar
3 Soosai Antony
4 Adam Allen
5 Babita Tripathy
9 stacey Davis
11 NULL NULL
I tried below query to display names into the corresponding risk, i am getting all the names as null value... Help needed please
;with cte as
(
SELECT [PROJ_RISK_DISCPLN].PROJ_ID,
[USER].USER_LST_NM + ' '+ [USER].USER_FIRST_NM as Name,
[RISK_DISCPLN].RISK_DISCPLN_NM,
[RISK_DISCPLN].RISK_DISCPLN_ID,
[USER].[USER_ID]
FROM dbo.[PROJ_RISK_DISCPLN]
left join [dbo].[USER]
on [PROJ_RISK_DISCPLN].RISK_OWN_USER_ID = [dbo].[USER].[USER_ID]
left join dbo.[RISK_DISCPLN] on
[PROJ_RISK_DISCPLN].RISK_DISCPLN_ID = [RISK_DISCPLN].RISK_DISCPLN_ID
)
select *
from
(
select c1.PROJ_ID,
c1.RISK_DISCPLN_NM,
STUFF(
(SELECT ', ' + c2.Name
FROM cte c2
where c1.PROJ_ID = c2.PROJ_ID
and c1.RISK_DISCPLN_ID = c2.RISK_DISCPLN_ID
FOR XML PATH (''))
, 1, 1, '') AS Name
from cte c1
) d
pivot
(
max(Name)
for RISK_DISCPLN_NM in ([LegalRisk Owner],[institutional Risk Owner],[Market Risk Owner])
) piv

I got answer, Instead [LegalRisk Owner],[institutional Risk Owner],[Market Risk Owner]
i have to use [LegalRisk],[institutional Risk],[Market Risk] ....

Related

Concatenate values with LEFT join

While searching, I came across a very similar post here
but I have an additional question to what has been posted there already.
id|person_name|department_name|phone_number
--+-----------+---------------+------------
1 |"John" |"Finance" |"023451"
1 |"John" |"Finance" |"99478"
1 |"John" |"Finance" |"67890"
1 |"John" |"Marketing" |"023451"
1 |"John" |"Marketing" |"99478"
1 |"John" |"Marketing" |"67890"
2 |"Barbara" |"Finance" |""
3 |"Michelle" |"" |"005634"
Lets say I want the final result as:
id|person_name|department_name|phone_number
--+-----------+---------------+------------
1 |"John" |"Finance" |"023451", "99478", "67890"
1 |"John" |"Marketing" |"023451", "99478", "67890"
2 |"Barbara" |"Finance" |""
3 |"Michelle" |"" |"005634"
basically similar results from phone_number concatenated; then can you advise what should I be doing ? I tried GROUP_CONCAT with DISTINCT but it didn't help.
So this will pivot and comma delimit your Numbers which I believe is the desired effect? This is a SQL Server solution
declare #t table (OrderedID int, EmpName varchar(50), EmpDep varchar(50), Num varchar(50))
insert into #t
values
(1,'John','Dep1','123')
,(1,'John','Dep1','456')
,(1,'John','Dep2','789')
,(2,'Doug','Dep1','987')
,(2,'Doug','Dep1','654')
,(2,'Steve','Dep2','321')
Select
*
From #t
SELECT distinct e.EmpName,
e.EmpDep,
LEFT(r.Num , LEN(r.Num)-1) num
FROM #t e
CROSS APPLY
(
SELECT r.Num + ', '
FROM #t r
where e.EmpName = r.EmpName
and e.EmpDep = r.EmpDep
FOR XML PATH('')
) r (Num)
Ouput:
EmpName EmpDep num
Doug Dep1 987, 654
John Dep1 123, 456
John Dep2 789
Steve Dep2 321

MySQL query aggregate MAX and subquery

Is there a way to get value from a subquery in where inside select?
stop_link Table
id | duid | domain_id
1 | 1 | 1
2 | 2 | 1
3 | 1 | 2
4 | 2 | 2
5 | 3 | 1
Result that I want (assume domain_id = 2)
duid | domain_id
3 | 2
Query (not working):
INSERT INTO stop_link (
duid,
domain_id)
SELECT
IFNULL(MAX(sl.duid), 0) + 1 AS duid,
sl.domain_id
FROM
stop_link sl
WHERE sl.domain_id = (SELECT sd.id FROM stop_domain sd LIMIT 1)
Query working but I wish to avoid the Set Variable:
SET #domain_id = (SELECT sd.id FROM stop_domain sd LIMIT 1);
SELECT
IFNULL(MAX(sl.duid), 0) + 1 AS duid
, #domain_id
FROM
stop_link sl
WHERE sl.domain_id = #domain_id;
Do you mean something like this:
/*Your example Table*/
DECLARE #T
TABLE(ID INT,duid INT,domain_id INT)
INSERT INTO #T
VALUES
(1 , 1 , 1 ),
(2 , 2 , 1),
(3 , 1 , 2),
(4 , 2 , 2),
(5 , 3 , 1)
--The query
SELECT domain_id,Isnull(max(duid),0)+1 [newId]
FROM #T
GROUP BY domain_id
No need of max():
SELECT
IFNULL(sl.duid, 0) + 1 AS duid,
sl.domain_id
FROM
stop_link sl
WHERE sl.domain_id = (SELECT sd.id FROM stop_domain sd LIMIT 1)
ORDER by sl.id DESC
LIMIT 1
Changed answer based on new info from the comments. It sounds like you've got only_full_group_by enabled in your sql_mode. Your query would probably work with that disabled, but the following may also work for you:
INSERT INTO stop_link (
duid,
domain_id)
SELECT
IFNULL(MAX(sl.duid), 0) + 1 AS duid,
sl.domain_id
FROM
stop_link sl
WHERE sl.domain_id = (SELECT sd.id FROM stop_domain sd LIMIT 1)
-- ORDER by sl.domain_id DESC LIMIT 1 # Removed in favor of the following line
GROUP BY sl.domain_id HAVING MAX(sl.id)
;
Note that the subquery may not be returning the stop_domain.id that you want it to be -- you might have intended to select MAX(sd.id), or perhaps you just removed a WHERE sd.url='foo' for clarity's sake.

How to write an SQL query that expands a comma delimited field into multiple fields?

First of all...I know it's bad to have comma separated values in tables and no I'm not able to change it.
I have several tables that contain the following data:
************** Table 1 **********
stock_id products_id stock_attributes
5271 279 1559,2764
************** Table 2 *********************
products_attributes_id products_id options_id options_values_id
1559 279 2 8
2764 279 3 63
************** Table 3 ************************
products_options_id products_options_name
2 Size
3 Color
************** Table 4 *****************
products_options_values_id products_options_values_name
14 Pink
63 Mint
13 Black
8 S
9 M
10 L
11 XL
What I'd like to do is create a query to take the field stock_attributes in Table 1 and expand it using the information in the Tables 2, 3 & 4 so I end up with the following:
*********** Resulting Table **********
stock_id products_id opt1 opt2 opt3 opt4
5271 279 Size S Color Mint
I can do this programmatically after the fact but I'm curious if it can be done in a single SQL query. I've found similar questions and answer on how to select a particular value from a comma delimited field but nothing to do this. Any help is appreciated.
If the number of attributes are fixed. You can simply split the column into multiple like this.
SELECT stock_id, products_id,
PARSENAME(REPLACE(stock_attributes,',','.'),2) a1,
PARSENAME(REPLACE(stock_attributes,',','.'),1) a2
FROM Table1
To further expand and include the values from other tables, you can do simple JOIN
select pTable.stock_id, pTable.products_id,
(select products_options_name from Table3 where products_options_id = t2.options_id) as opt1,
(select products_options_values_name from Table4 where products_options_values_id = t2.options_values_id) as opt2,
(select products_options_name from Table3 where products_options_id = t3.options_id) as opt3,
(select products_options_values_name from Table4 where products_options_values_id = t3.options_values_id) as opt4
from
(
SELECT stock_id, products_id,
PARSENAME(REPLACE(stock_attributes,',','.'),2) a1,
PARSENAME(REPLACE(stock_attributes,',','.'),1) a2
FROM Table1
) pTable
join Table2 t2 on pTable.a1 = t2.products_attributes_id and pTable.products_id = t2.products_id
join Table2 t3 on pTable.a2 = t3.products_attributes_id and pTable.products_id = t3.products_id
This is very long. So I stop until the point where have the data ready for a Dynamic SQL Pivot
This can solve any number of atributes. Just save the output to a table o create a stored procedure to have the data for the dynamic pivot.
tmp: Split the comma-separated values into rows
product_attributes: is just a select to see the result from the recursive function. Can't be removed
product_details: join the attributes with the other tables to get their values
product_attribute_count: each attribute needs a row_number so you can create header later. Also I realize you didnt need the COUNT()
product_pre_pivot: create headers and value, for option_id and option_value_id
product_pivot: separated those pair header into a single column
You can test each step to see the result .... SELECT * FROM [STEP#]
SQL Fiddle Demo
Code:
;WITH tmp([stock_id], [products_id], products_attributes_id, data_r) AS
(
SELECT
[stock_id], [products_id],
LEFT([stock_attributes], Charindex(',', [stock_attributes] + ',') - 1),
STUFF([stock_attributes], 1, Charindex(',', [stock_attributes] + ','), '')
FROM
Table1
UNION ALL
SELECT
[stock_id], [products_id],
LEFT(data_r, Charindex(',', data_r + ',') - 1),
STUFF(data_r, 1, Charindex(',', data_r + ','), '')
FROM
tmp
WHERE
data_r > ''
), product_attributes AS
(
SELECT
[stock_id], [products_id],
[products_attributes_id]
FROM
tmp
), product_details AS
(
SELECT
pa.*,
t2.options_id, t2.options_values_id,
t3.[products_options_name],
t4.[products_options_values_name]
FROM
product_attributes pa
JOIN
Table2 t2 ON pa.[products_id] = t2.[products_id]
AND pa.[products_attributes_id] = t2.[products_attributes_id]
JOIN
Table3 t3 ON t2.[options_id] = t3.[products_options_id]
JOIN
Table4 t4 ON t2.[options_values_id] = t4.[products_options_values_id]
), product_attribute_count AS
(
SELECT
*,
row_number() over (PARTITION BY products_id
ORDER BY options_id) as rn,
count(*) over (partition by products_id) cnt
FROM
product_details
), product_pre_pivot AS
(
SELECT
stock_id, products_id,
'opt' + CAST(2*rn - 1 as varchar(max)) as header1,
products_options_name as d_value,
'opt' + CAST(2*rn as varchar(max)) as header2,
products_options_values_name as a_value
FROM
product_attribute_count
), product_pivot AS
(
SELECT
stock_id, products_id,
header1 header, d_value value
FROM
product_pre_pivot
UNION ALL
SELECT
stock_id, products_id,
header2 header, a_value value
FROM
product_pre_pivot
)
SELECT *
FROM product_pivot
ORDER BY header
OUTPUT
| stock_id | products_id | header | value |
|----------|-------------|--------|-------|
| 5271 | 279 | opt1 | Size |
| 5271 | 279 | opt2 | S |
| 5271 | 279 | opt3 | Color |
| 5271 | 279 | opt4 | Mint |

Finding duplicate names where first name can be an initial or full name

I am trying to find duplicates by comparing the first name and surname columns in a table. The first name can be a name or an initial.
Reading other posts I have managed to figure out how to get the duplicate surnames and list the first letter for first name. But I am unsure how to only show rows where there is a match of surname and the first letter of the first name.
SELECT *
FROM table AS a
INNER JOIN (
SELECT LEFT( firstname, 1 ) , surname
FROM table
GROUP BY surname
HAVING COUNT( * ) > 1
) AS b ON a.surname = b.surname
id | firstname | surname
**************************
1 | joe | bloggs
2 | j | bloggs
3 | s | bloggs
4 | f | doe
5 | frank | spencer
Currently this query would return
1 | joe | bloggs
2 | j | bloggs
3 | s | bloggs
Result I would like would just contain the possible duplicates.
1 | joe | bloggs
2 | j | bloggs
I don't quite get what you want. Yor provided a query, your current table and the expected result.
I've just created your table, run your query and got the expected result. What is wrong with this?
SELECT FROM table1 AS a
INNER JOIN (
SELECT surname FROM table1
GROUP BY surname
HAVING COUNT(*) > 1
) AS b ON a.surname = b.surname
This effectively result in your expected result:
joe | bloggs
j | bloggs
Or am I missing something?
After re-reading... are you expecting to get only this?
j | bloggs
If that is the case, use this:
SELECT * FROM table1 AS a
INNER JOIN (
SELECT surname FROM table1
GROUP BY surname
HAVING COUNT(*) > 1
) AS b ON a.surname = b.surname
WHERE CHAR_LENGTH(firstname) = 1
Edit:
After the expected result was properly explained I conclude the query should be:
SELECT a.firstname, a.surname FROM t1 AS a
INNER JOIN (
SELECT LEFT(firstname, 1) AS firstChar, surname FROM t1
GROUP BY surname, firstChar
HAVING COUNT(surname) > 1
) AS b ON a.surname = b.surname AND b.firstChar = LEFT(a.firstname, 1)
Working example
You probably don't want to use initials all the time, e.g., if you always strip to initials you might consider Bob X the same as Bill X.
So you need to check three cases.
both firstnames are initials
both firstnames are non initials
only one firstname is an intial
So you can work with string methods of Mysql to check the length of either firstname and check the proper case.
I would join the table to itself like so:
select * into #temp from (
SELECT 1, 'joe', 'bloggs' UNION
SELECT 2, 'j', 'bloggs' UNION
SELECT 3, 'f', 'doe' UNION
SELECT 4, 'frank', 'spencer' UNION
SELECT 5, 'steven', 'woo' UNION
SELECT 6, 'steve', 'woo' UNION
SELECT 7, 'stanley', 'woo'
) x (id, firstname, surname)
select
*
from
#temp l
inner join
#temp r
on
left(l.firstname, 1) = left(r.firstname, 1)
and
l.surname = r.surname
where
l.id < r.id
drop table #temp
the downside to this is that the steven and stanley match. I would suggest you think about creating a firstname alias table and use that to standardize the firstnames.

SQL Server Query or Tool to show Hierarchical Data

We have a general organizational table structure, think of it s a Tree or Pyramid Hierarchy. We basically have multiple "trees" we want to show. On for one company, one for another ETC.
Does anyone know of a good way to display this data? SQL Query would be nice, doubt it would be possible, but I wouldn't be against using some OTS tool (preferably free). I would also like to avoid some type of report. I don't need an actual solution just need to know if its possible. So if you say SQL if you can give me a 2 table example of showing a root a leave I would be happy.
Structure is pretty general
And each table is linked through a surrogate key CompanyID, CompanyGroupID, etc.
Any suggestions on ways we could display/query for this data? Last resort is to write a quick C# Windows Application...
We would like to see it in tree form:
-- 1-Company
-- / \
-- CompanyGroupA CompanyGroupB
-- / \ \
-- CompanyStoreA1 CompanyStoreA1 CompanyStoreB
-- / \ / \
--Employee A B C
In attempt to please the masses here is an example test script to populate the query.
DECLARE #Company table (id int, name varchar(40) )
INSERT #Company VALUES (1,'Living Things' )
INSERT #Company VALUES (2,'Boring Company' )
DECLARE #CompanyGroup table (id int, name varchar(40), CompanyID int)
INSERT #CompanyGroup VALUES (1,'Pets',1 )
INSERT #CompanyGroup VALUES (2,'Humans',1 )
INSERT #CompanyGroup VALUES (3,'Electronics',2 )
INSERT #CompanyGroup VALUES (4,'Food',2 )
DECLARE #CompanyStore table (id int, name varchar(40), CompanyGroupID int)
INSERT #CompanyStore VALUES (1,'PetsStoreA',1 )
INSERT #CompanyStore VALUES (2,'PetsStoreB',1 )
INSERT #CompanyStore VALUES (3,'PetsStoreC',1 )
INSERT #CompanyStore VALUES (4,'PetsStoreD', 1)
INSERT #CompanyStore VALUES (5,'HumansStore',2 )
INSERT #CompanyStore VALUES (6,'FoodStore',3 )
The final solution was pretty awesome I modified the usp_DrawTree to accept varchar vs ints because i had to make my query ids unique. I then just did a select/union all and built the parent child relationship.
select * into #TreeData from (
select ID='C' + cast(id as varchar(10)),
ParentID=null,
DataForBox=name + '(' + cast(id as varchar(10)) + ')',
ExtraInfo='',
SortColumn=name
from Company c
)
union all (
select ID='CG' + cast(id as varchar(10)),
ParentID=cg.CompanyID ,
DataForBox=name + '(' + cast(id as varchar(10)) + ')',
ExtraInfo='',
SortColumn=name
from CompanyGroup cg join Company c on c.ID=cg.CompanyID
)
//union all rest of hierarchy
)
Brad Schulz to the rescue in the form of usp_DrawTree.
you don't provide any table structure, so here is a sample of a recursive CTE processing a tree structure:
--go through a nested table supervisor - user table and display the chain
DECLARE #Contacts table (id varchar(6), first_name varchar(10), reports_to_id varchar(6))
INSERT #Contacts VALUES ('1','Jerome', NULL ) -- tree is as follows:
INSERT #Contacts VALUES ('2','Joe' ,'1') -- 1-Jerome
INSERT #Contacts VALUES ('3','Paul' ,'2') -- / \
INSERT #Contacts VALUES ('4','Jack' ,'3') -- 2-Joe 9-Bill
INSERT #Contacts VALUES ('5','Daniel','3') -- / \ \
INSERT #Contacts VALUES ('6','David' ,'2') -- 3-Paul 6-David 10-Sam
INSERT #Contacts VALUES ('7','Ian' ,'6') -- / \ / \
INSERT #Contacts VALUES ('8','Helen' ,'6') -- 4-Jack 5-Daniel 7-Ian 8-Helen
INSERT #Contacts VALUES ('9','Bill ' ,'1') --
INSERT #Contacts VALUES ('10','Sam' ,'9') --
DECLARE #Root_id char(4)
--get complete tree---------------------------------------------------
SET #Root_id=null
PRINT '#Root_id='+COALESCE(''''+#Root_id+'''','null')
;WITH StaffTree AS
(
SELECT
c.id, c.first_name, c.reports_to_id, c.reports_to_id as Manager_id, cc.first_name AS Manager_first_name, 1 AS LevelOf
FROM #Contacts c
LEFT OUTER JOIN #Contacts cc ON c.reports_to_id=cc.id
WHERE c.id=#Root_id OR (#Root_id IS NULL AND c.reports_to_id IS NULL)
UNION ALL
SELECT
s.id, s.first_name, s.reports_to_id, t.id, t.first_name, t.LevelOf+1
FROM StaffTree t
INNER JOIN #Contacts s ON t.id=s.reports_to_id
WHERE s.reports_to_id=#Root_id OR #Root_id IS NULL OR t.LevelOf>1
)
SELECT * FROM StaffTree
--get all below 2---------------------------------------------------
SET #Root_id=2
PRINT '#Root_id='+COALESCE(''''+#Root_id+'''','null')
;WITH StaffTree AS
(
SELECT
c.id, c.first_name, c.reports_to_id, c.reports_to_id as Manager_id, cc.first_name AS Manager_first_name, 1 AS LevelOf
FROM #Contacts c
LEFT OUTER JOIN #Contacts cc ON c.reports_to_id=cc.id
WHERE c.id=#Root_id OR (#Root_id IS NULL AND c.reports_to_id IS NULL)
UNION ALL
SELECT
s.id, s.first_name, s.reports_to_id, t.id, t.first_name, t.LevelOf+1
FROM StaffTree t
INNER JOIN #Contacts s ON t.id=s.reports_to_id
WHERE s.reports_to_id=#Root_id OR #Root_id IS NULL OR t.LevelOf>1
)
SELECT * FROM StaffTree
--get all below 6---------------------------------------------------
SET #Root_id=6
PRINT '#Root_id='+COALESCE(''''+#Root_id+'''','null')
;WITH StaffTree AS
(
SELECT
c.id, c.first_name, c.reports_to_id, c.reports_to_id as Manager_id, cc.first_name AS Manager_first_name, 1 AS LevelOf
FROM #Contacts c
LEFT OUTER JOIN #Contacts cc ON c.reports_to_id=cc.id
WHERE c.id=#Root_id OR (#Root_id IS NULL AND c.reports_to_id IS NULL)
UNION ALL
SELECT
s.id, s.first_name, s.reports_to_id, t.id, t.first_name, t.LevelOf+1
FROM StaffTree t
INNER JOIN #Contacts s ON t.id=s.reports_to_id
WHERE s.reports_to_id=#Root_id OR #Root_id IS NULL OR t.LevelOf>1
)
SELECT * FROM StaffTree
OUTPUT:
#Root_id=null
id first_name reports_to_id Manager_id Manager_first_name LevelOf
------ ---------- ------------- ---------- ------------------ -----------
1 Jerome NULL NULL NULL 1
2 Joe 1 1 Jerome 2
9 Bill 1 1 Jerome 2
10 Sam 9 9 Bill 3
3 Paul 2 2 Joe 3
6 David 2 2 Joe 3
7 Ian 6 6 David 4
8 Helen 6 6 David 4
4 Jack 3 3 Paul 4
5 Daniel 3 3 Paul 4
(10 row(s) affected)
#Root_id='2 '
id first_name reports_to_id Manager_id Manager_first_name LevelOf
------ ---------- ------------- ---------- ------------------ -----------
2 Joe 1 1 Jerome 1
3 Paul 2 2 Joe 2
6 David 2 2 Joe 2
7 Ian 6 6 David 3
8 Helen 6 6 David 3
4 Jack 3 3 Paul 3
5 Daniel 3 3 Paul 3
(7 row(s) affected)
#Root_id='6 '
id first_name reports_to_id Manager_id Manager_first_name LevelOf
------ ---------- ------------- ---------- ------------------ -----------
6 David 2 2 Joe 1
7 Ian 6 6 David 2
8 Helen 6 6 David 2
(3 row(s) affected)
EDIT based on OP's given tables and data:
try something like this:
SET NOCOUNT ON
DECLARE #Company table (id int, name varchar(40) )
INSERT #Company VALUES (1,'Living Things' )
INSERT #Company VALUES (2,'Boring Company' )
DECLARE #CompanyGroup table (id int, name varchar(40), CompanyID int)
INSERT #CompanyGroup VALUES (1,'Pets' ,1 )
INSERT #CompanyGroup VALUES (2,'Humans' ,1 )
INSERT #CompanyGroup VALUES (3,'Electronics' ,2 )
INSERT #CompanyGroup VALUES (4,'Food' ,2 )
DECLARE #CompanyStore table (id int, name varchar(40), CompanyGroupID int)
INSERT #CompanyStore VALUES (1,'PetsStoreA' ,1 )
INSERT #CompanyStore VALUES (2,'PetsStoreB' ,1 )
INSERT #CompanyStore VALUES (3,'PetsStoreC' ,1 )
INSERT #CompanyStore VALUES (4,'PetsStoreD' ,1)
INSERT #CompanyStore VALUES (5,'HumansStore' ,2 )
INSERT #CompanyStore VALUES (6,'FoodStore' ,3 )
--not provided by the OP, so I made it up
DECLARE #CompanyEmployees table (id int, name varchar(10), reports_to_id int, CompanyStoreID int)
INSERT #CompanyEmployees VALUES (1,'Jerome', NULL ,1) -- tree is as follows:
INSERT #CompanyEmployees VALUES (2,'Joe' ,1 ,1) -- PetsStoreA PetsStoreB PetStoreC FoodStore
INSERT #CompanyEmployees VALUES (3,'Paul' ,2 ,1) -- 1-Jerome 11-Alan 14-Ben 18-apple
INSERT #CompanyEmployees VALUES (4,'Jack' ,3 ,1) -- / \ / \ / / \
INSERT #CompanyEmployees VALUES (5,'Daniel',3 ,1) -- 2-Joe 9-Bill 12-Ally 13-Abby 15-Bill 19-pear 20-grape
INSERT #CompanyEmployees VALUES (6,'David' ,2 ,1) -- / \ \ / \ /
INSERT #CompanyEmployees VALUES (7,'Ian' ,6 ,1) -- 3-Paul 6-David 10-Sam 16-Bjorn 17-Benny 21-rasin
INSERT #CompanyEmployees VALUES (8,'Helen' ,6 ,1) -- / \ / \
INSERT #CompanyEmployees VALUES (9,'Bill ' ,1 ,1) -- 4-Jack 5-Daniel 7-Ian 8-Helen
INSERT #CompanyEmployees VALUES (10,'Sam' ,9 ,1) --
INSERT #CompanyEmployees VALUES (11,'Alan' ,NULL ,2) --to see all trees, scroll--->>
INSERT #CompanyEmployees VALUES (12,'Ally' ,11 ,2) --
INSERT #CompanyEmployees VALUES (13,'Abby' ,11 ,2) --
INSERT #CompanyEmployees VALUES (14,'Ben' ,NULL ,3) --
INSERT #CompanyEmployees VALUES (15,'Bill' ,14 ,3) --
INSERT #CompanyEmployees VALUES (16,'Bjorn',15 ,3) --
INSERT #CompanyEmployees VALUES (17,'Benny',15 ,3) --
INSERT #CompanyEmployees VALUES (18,'apple',NULL ,6) --
INSERT #CompanyEmployees VALUES (19,'pear' ,18 ,6) --
INSERT #CompanyEmployees VALUES (20,'grape',18 ,6) --
INSERT #CompanyEmployees VALUES (21,'rasin',21 ,6) --
SET NOCOUNT OFF
;WITH StaffTree AS
(
SELECT
c.id, c.name, c.reports_to_id, c.reports_to_id as Manager_id, cc.name AS Manager_name, 1 AS LevelOf, c.CompanyStoreID
FROM #CompanyEmployees c
LEFT OUTER JOIN #CompanyEmployees cc ON c.reports_to_id=cc.id
WHERE c.reports_to_id IS NULL
UNION ALL
SELECT
s.id, s.name, s.reports_to_id, t.id, t.name, t.LevelOf+1, s.CompanyStoreID
FROM StaffTree t
INNER JOIN #CompanyEmployees s ON t.id=s.reports_to_id
)
SELECT
c.id AS CompanyID, c.name AS CompanyName
,g.id AS CompanyGroupID, g.name AS CompanyName
,s.id AS CompanyStoreID, s.name AS CompanyStoreName
,t.id AS EmployeeID, t.name as EmployeeName, t.Manager_id, t.Manager_name, t.LevelOf
FROM #Company c
LEFT JOIN #CompanyGroup g ON c.id=g.CompanyID
LEFT JOIN #CompanyStore s ON g.id=s.CompanyGroupID
LEFT JOIN StaffTree t ON s.id=t.CompanyStoreID
ORDER BY c.name,g.name,s.name,s.ID,t.LevelOf,t.name
OUTPUT:
CompanyID CompanyName CompanyGroupID CompanyName CompanyStoreID CompanyStoreName EmployeeID EmployeeName Manager_id Manager_name LevelOf
--------- -------------- -------------- ----------- -------------- ---------------- ----------- ------------ ----------- ------------ -------
2 Boring Company 3 Electronics 6 FoodStore 18 apple NULL NULL 1
2 Boring Company 3 Electronics 6 FoodStore 20 grape 18 apple 2
2 Boring Company 3 Electronics 6 FoodStore 19 pear 18 apple 2
2 Boring Company 4 Food NULL NULL NULL NULL NULL NULL NULL
1 Living Things 2 Humans 5 HumansStore NULL NULL NULL NULL NULL
1 Living Things 1 Pets 1 PetsStoreA 1 Jerome NULL NULL 1
1 Living Things 1 Pets 1 PetsStoreA 9 Bill 1 Jerome 2
1 Living Things 1 Pets 1 PetsStoreA 2 Joe 1 Jerome 2
1 Living Things 1 Pets 1 PetsStoreA 6 David 2 Joe 3
1 Living Things 1 Pets 1 PetsStoreA 3 Paul 2 Joe 3
1 Living Things 1 Pets 1 PetsStoreA 10 Sam 9 Bill 3
1 Living Things 1 Pets 1 PetsStoreA 5 Daniel 3 Paul 4
1 Living Things 1 Pets 1 PetsStoreA 8 Helen 6 David 4
1 Living Things 1 Pets 1 PetsStoreA 7 Ian 6 David 4
1 Living Things 1 Pets 1 PetsStoreA 4 Jack 3 Paul 4
1 Living Things 1 Pets 2 PetsStoreB 11 Alan NULL NULL 1
1 Living Things 1 Pets 2 PetsStoreB 13 Abby 11 Alan 2
1 Living Things 1 Pets 2 PetsStoreB 12 Ally 11 Alan 2
1 Living Things 1 Pets 3 PetsStoreC 14 Ben NULL NULL 1
1 Living Things 1 Pets 3 PetsStoreC 15 Bill 14 Ben 2
1 Living Things 1 Pets 3 PetsStoreC 17 Benny 15 Bill 3
1 Living Things 1 Pets 3 PetsStoreC 16 Bjorn 15 Bill 3
1 Living Things 1 Pets 4 PetsStoreD NULL NULL NULL NULL NULL
(23 row(s) affected)
EDIT after OP's edit stating that We would like to see it in tree form.
The question is tagged sql-server-2008 and hierarchical-data, and the OP wants to do complex formatting for display f the data. However this type of processing and display is not the realm of TSQL and is a very clear example of where the application language should process and format flat data provided by a SQL query. I have provided such a query that could be used by an application to build a visual tree display. Also note that the simple tree example (no more than two children per parent) might not be very realistic and when many children exist for a single parent, the display will become difficult to construct and not pleasing to the eye.
You could use reporting services to display it back which you get with SQL 2008; if you are lucky it might be setup already -- if not its quite easy to do that. You could use the drill in features in reporting services to get allow your users to drill in and out of the data as needed very easily.
In terms of the query; does the tree grow or is it fixed? The SQL Query to get the data out from the database is quite simple though.
Select
CompanyName,
CompanyGroupName,
CompanyStoreName,
CompanyEmployeeForename,
CompanyEmployeeSurname
From tblCompanies com
left outer join tblCompanyGroups cg
on com.CompanyGroupID = cg.CompanyGroupID
Left outer Join tblCompanyStore cs
on com.CompanyID = cs.CompanyID
left outer join tblCompanyEmployees ce
on com.CompanyID = ce.CompanyName
I believe SQL Server 2008 offers a new data type to help with this scenario. Here is a link that I believe will help - http://msdn.microsoft.com/en-us/magazine/cc794278.aspx. I didn't see it in any comments, so hope this helps.