Data structures available in SQL Server 2008 - sql-server-2008

I am creating my first stored procedure in SQL Server 2008 and the problem I am attempting to solve needs some sort of data structure that can hold a string associated to multiple other strings, either a hash, or tree of some sort. However I cannot seem to find any examples of this online. Is there a way to use maps or trees in sql stored procedures, or is it assumed that this sort of heavy lifting by done outside in the code?
To be more specific on the problem, it deals with organizational charts. I have a query that can produce every employee and their immeadiate supervisor, but the output that is wanted by the rest of the team is a result set that has all people reporting below a given individual, but with an extra column for their supervisor below the given person. It might be easier to see than talk about.
For Example:
Jim and Billy report to Bob, Paul and April report to Kurt
Kurt and Ed report to Tim, Laurie and Bob report to George
George reports to Maggie
Maggie and Tim report to Jessica
With an input of Jessica, the information I need printed out would look like:
Jim reports to Maggie
Billy reports to Maggie
Paul reports to Tim
April reports to Tim
Kurt reports to Tim
Ed reports to Tim
Laurie reports to Maggie
Bob reports to Maggie
George reports to Maggie
Tim reports to Jessica
Maggie reports to Jessica
The real problem so far has been when running through the loop, I am going down one level at a time and finding everyone under the new records. This works fine if I just want the immeadiate supervisor, but in order to get that jump up to one level below the input I am needed to store the information some where, and I don't know what kind of structures would be supported within SQL for this task.

You might want to use recursion in order to pull info you want (use CTE).
Table structure is simple:
ID
Name
SupervisorID
Let me know if you need help with CTE.

here is a tree example:
--recursive CTE tree example
DECLARE #Contacts table (id int, first_name varchar(10), reports_to_id int)
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 int
--get complete tree---------------------------------------------------
SET #Root_id=null
PRINT '#Root_id='+COALESCE(''''+CONVERT(varchar(5),#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 ORDER BY LevelOf,first_name
--get 2 and all below---------------------------------------------------
SET #Root_id=2
PRINT '#Root_id='+COALESCE(''''+CONVERT(varchar(5),#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 ORDER BY LevelOf,first_name
--get 6 and all below---------------------------------------------------
SET #Root_id=6
PRINT '#Root_id='+COALESCE(''''+CONVERT(varchar(5),#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 ORDER BY LevelOf,first_name
OUTPUT:
#Root_id=null
id first_name reports_to_id Manager_id Manager_first_name LevelOf
----------- ---------- ------------- ----------- ------------------ -----------
1 Jerome NULL NULL NULL 1
9 Bill 1 1 Jerome 2
2 Joe 1 1 Jerome 2
6 David 2 2 Joe 3
3 Paul 2 2 Joe 3
10 Sam 9 9 Bill 3
5 Daniel 3 3 Paul 4
8 Helen 6 6 David 4
7 Ian 6 6 David 4
4 Jack 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
6 David 2 2 Joe 2
3 Paul 2 2 Joe 2
5 Daniel 3 3 Paul 3
8 Helen 6 6 David 3
7 Ian 6 6 David 3
4 Jack 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
8 Helen 6 6 David 2
7 Ian 6 6 David 2
(3 row(s) affected)

Related

Join 3 tables with Count

I am trying to write a simple query that will display all projects and their total number of team members, sorted alphabetically by project. If a project does not have assigned team members, that project should still be included in the output.
CREATE TABLE Project ( ID INT IDENTITY(1,1), ProjectName VARCHAR(50), DueDate
DATE)
CREATE TABLE Employee ( ID INT IDENTITY(1,1), EmployeeName VARCHAR(50) )
CREATE TABLE ProjectAssignment ( ID INT IDENTITY(1,1), ProjectID INT,
EmployeeID INT)
INSERT INTO Project VALUES ('Alpha', '1/1/2040'), ('Bravo', '3/1/2030'),
('Charlie', '2/1/2017'), ('Delta', '4/1/2017')
INSERT INTO Employee VALUES ('John'), ('Beth'), ('Tom'), ('Kim'), ('Jack')
INSERT INTO ProjectAssignment VALUES (1, 1), (1, 2), (2, 2), (2, 3), (3,
3), (3, 4), (1, 3)
--TABLE Project:
ID ProjectName DueDate
1 Alpha 2040-01-01
2 Bravo 2030-03-01
3 Charlie 2017-02-01
4 Delta 2017-04-01
--TABLE Employee:
ID EmployeeName
1 John
2 Beth
3 Tom
4 Kim
5 Jack
--TABLE ProjectAssignment:
ID ProjectID EmployeeID
1 1 1
2 1 2
3 2 2
4 2 3
5 3 3
6 3 4
7 1 3
Here is my wrong query:
SELECT n.ProjectName, Count(t.ProjectID) as NumMembers
FROM Project p
LEFT JOIN ProjectAssignment t ON p.EmployeeID = t.EmployeeID
LEFT JOIN employee e ON e.ProjectID = t.ProjectID
GROUP BY n.Project
ORDER BY n.Project
Desired Result:
| ProjectName | NumMembers |
+-------------+-------------+
| Alpha | 3 |
| Bravo | 2 |
| Charlie | 2 |
| Delta | null |
Please try this Mysql query. This will resolve your issue. We dont' require employee table join. If you are not taking any data from employee table then don't add employee table in join.
SELECT
p.name AS ProjectName,
Count( t.employeeID ) AS NumMembers
FROM
Project p
LEFT JOIN ProjectAssignment t ON p.id = t.projectID
GROUP BY
p.name
Output:
Project name NumMembers
Alpha 3
Bravo 2
Charlie 2
Delta 0
Few things
LEFT JOIN ProjectAssignment t ON p.EmployeeID = t.EmployeeID
is wrong as you can see p.EmployeeID do not exists on table Project
your join to employee is not needed at all
also finally i do not know how your fields names are. you post Name in sample data and projectName is used in your query and ddl (changed to your DDL instead of your query)
SELECT p.ProjectName, Count(DISTINCT pa.EmployeeID) as NumMembers
FROM Project p
LEFT JOIN ProjectAssignment pa ON p.ID = pa.ProjectID
GROUP BY p.ID, p.ProjectName
ORDER BY p.ProjectName
http://sqlfiddle.com/#!18/36df5/1
SELECT n.ProjectName, Count(t.ProjectID) as NumMembers FROM Project n LEFT JOIN ProjectAssignment t ON n.id = t.ProjectID GROUP BY t.ProjectID ORDER BY n.ProjectName
run this query
Just use this ( it seems join conditions are mixed ):
SELECT p.ProjectName, Count(t.ProjectID) as NumMembers
FROM Project p
LEFT JOIN ProjectAssignment t ON p.ID = t.ProjectID
LEFT JOIN employee e ON t.EmployeeID = e.ID
GROUP BY p.ProjectName
ORDER BY p.ProjectName;
ProjectName NumMembers
Alpha 3
Bravo 2
Charlie 2
Delta 0
SQL Fiddle Demo

SQL Select Statement customer with two or more banks

I have this table
CustomerID CustomerName Bank Amount
1 Martin BDO Php 55.00
1 Martin CBA Php 150.00
2 Grace BDO Php 45.00
2 Grace BDO Php 4100.00
3 Blake BPI Php 120
I need a sql statement that will display customer with accounts on two different banks.
The result should be
CustomerID CustomerName Bank Amount
1 Martin BDO Php 55.00
1 Martin CBA Php 150.00
How can I get this result?
You can use GROUP BY with HAVING to do this, e.g.:
SELECT *
FROM customer
WHERE customerID IN (
SELECT customerID
FROM customer
GROUP BY customerID
HAVING COUNT(DISTINCT(Bank)) > 1
);
There are several different ways you can get the result that you want. You could join on a subquery that gets a list of CustomerIds with more than one distinct Bank:
select
m1.CustomerId,
m1.CustomerName,
m1.Bank,
m1.Amount
from mytable m1
inner join
(
select
CustomerId
from mytable
group by CustomerId
having count(distinct Bank) >= 2
) m2
on m1.CustomerId = m2.CustomerId;
Or you could use a WHERE EXISTS to also get the result:
select
m.CustomerId,
m.CustomerName,
m.Bank,
m.Amount
from mytable m
where exists (select 1
from mytable m2
where m.CustomerId = m2.CustomerId
and m.Bank <> m2.Bank);
Here is a demo

Query for group by rows but keeping the minimum date

I have the next table with data:
user group dt_action
----- ----- ---------
John salvage 2016-3-2
Dennis fire 2016-1-1
Martha fire 2016-12-23
John rescue 2016-1-20
John salvage 2017-1-26
Developer NULL 2016-5-6
Dennis several 2016-4-29
Martha fire 2003-1-1
My idea is to group by the category "group", counting the amount of gorups per each user, but on the datetime field, I want to keep the minim date of each group sumarized. The result should be something like that:
user group count_group dt_action_min
---- ----- ----------- -------------
John salvage 2 2016-3-2
John rescue 1 2016-1-20
Dennis fire 1 2016-1-1
Dennis several 1 2016-4-29
Martha fire 2 2003-1-1
Developer NULL 1 2016-5-6
This is a query that long time ago has stolen my dream, but I can get it!
Thanks a lot,
Dani
CREATE table/INSERT data
CREATE TABLE DATA
(`user` VARCHAR(9), `group` VARCHAR(7), `dt_action` VARCHAR(10))
;
INSERT INTO DATA
(`user`, `group`, `dt_action`)
VALUES
('John', 'salvage', '2016-3-2'),
('Dennis', 'fire', '2016-1-1'),
('Martha', 'fire', '2016-12-23'),
('John', 'rescue', '2016-1-20'),
('John', 'salvage', '2017-1-26'),
('Developer', NULL, '2016-5-6'),
('Dennis', 'several', '2016-4-29'),
('Martha', 'fire', '2003-1-1')
;
Query
Replace data with your own table name
SELECT
`data`.`user`
, `data`.`group`
, `data_group`.`count_group`
, `data_group`.`min_dt_action`
FROM
`data`
INNER JOIN (
SELECT
`data`.user
, `data`.`group`
, COUNT(*) count_group
, MIN(`data`.`dt_action`) min_dt_action
FROM
`data`
GROUP BY
`data`.user
, `data`.`group`
) data_group
ON
`data`.`user` = data_group.`user`
AND
`data`.dt_action = data_group.min_dt_action
ORDER BY
`data_group`.`count_group` DESC
Result
user group count_group min_dt_action
--------- ------- ----------- ---------------
Martha fire 2 2003-1-1
John salvage 2 2016-3-2
John rescue 1 2016-1-20
Developer (NULL) 1 2016-5-6
Dennis fire 1 2016-1-1
Dennis several 1 2016-4-29

SQL PIVOT QUERY ISSUE

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] ....

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.