SQL Server Query or Tool to show Hierarchical Data - sql-server-2008

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.

Related

How to retrieve data solely by foreign key in MySQL?

The mission: Visualize the patients that were treated by surgeons.
Table: patients
id_patient
name
last_name
Table: doctors
id_doctor
name
last_name
speciality ("surgeon" is one of the possibilities)
Table: visits
id_visit
id_patient_fk (foreign key)
id_doctor_fk (foreign key)
With the id_doctor_fk pointing to id_doctor, I have to see if that doctor is a surgeon, right? Is this possible? I gave up, so I ask.
If you want patients who have seen a surgeon, you can use exists:
select p.*
from patients p
where exists (select 1
from visits v join
doctors d
on d.id_doctor = v.id_doctor_pk
where v.id_patient_fk = p.id_patient and
d.specialty = 'surgeon'
);
i created an example for your question . i hope this is help you:
CREATE TABLE #patients2 (
id_patient int,
[name] VARCHAR(100),
last_name VARCHAR(100)
);
CREATE TABLE #doctors2 (
id_doctor int,
[name] VARCHAR(100),
last_name VARCHAR(100),
speciality VARCHAR(100),
);
CREATE TABLE #dvisits2 (
id_visit int,
id_patient_fk int,
id_doctor_fk int
);
--drop table #table1
INSERT INTO #patients2
(id_patient, [name], last_name)
VALUES
(1,'patient1','last_name1'),
(2,'patient2','last_name2'),
(3,'patient3','last_name3'),
(4,'patient4','last_name4'),
(5,'patient5','last_name5'),
(6,'patient6','last_name6'),
(7,'patient7','last_name7'),
(8,'patient8','last_name8');
INSERT INTO #doctors2
(id_doctor, [name], last_name, speciality )
VALUES
(1,'doctor1','last_name1','surgeon'),
(2,'doctor2','last_name2','not surgeon'),
(3,'doctor3','last_name3','surgeon'),
(4,'doctor4','last_name4','not surgeon'),
(5,'doctor5','last_name5','surgeon'),
(6,'doctor6','last_name6','surgeon'),
(7,'doctor7','last_name7','not surgeon'),
(8,'doctor8','last_name8','surgeon');
INSERT INTO #dvisits2
(id_visit, id_doctor_fk,id_patient_fk)
VALUES
(1,1,1),
(2,2,2),
(3,3,3),
(4,4,4),
(5,5,5),
(6,6,6),
(7,7,7),
(8,8,8);
select * from #patients2 p
join #dvisits2 dv on p.id_patient = dv.id_patient_fk
join #doctors2 doc on dv.id_doctor_fk = doc.id_doctor
where doc.speciality = 'surgeon'
result =
id_patient [name] last_name id_visit id_patient_fk id_doctor_fk speciality id_doctor [name] last_name
1 patient1 last_name1 1 1 1 surgeon 1 doctor1 last_name1
1 patient1 last_name1 1 1 1 surgeon 1 doctor1 last_name1
3 patient3 last_name3 3 3 3 surgeon 3 doctor3 last_name3
3 patient3 last_name3 3 3 3 surgeon 3 doctor3 last_name3
5 patient5 last_name5 5 5 5 surgeon 5 doctor5 last_name5
6 patient6 last_name6 6 6 6 surgeon 6 doctor6 last_name6
8 patient8 last_name8 8 8 8 surgeon 8 doctor8 last_name8

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

How to select a row with maximum value for a column in MySQL?

*None of other available answers solved my problem
I have a table t like this
id,cc,count
'1','HN','22'
'1','US','18'
'1','VN','1'
'2','DK','2'
'2','US','256'
'3','SK','1'
'3','US','66310'
'4','UA','2'
'4','US','263'
'6','FR','7'
'6','US','84'
'9','BR','3'
I want to get the rows for ids with maximum count, like below:
id,cc,count
'1','HN','22'
'2','US','256'
'3','US','66310'
'4','US','263'
'6','US','84'
'9','BR','3'
My current code is like this but I am not getting the expected results:
SELECT t.* FROM t
JOIN (
SELECT
t.id,t.cc
,max(t.count) as max_slash24_count
FROM t
group by t.id,t.cc
) highest
ON t.count = highest.max_slash24_count
and t.cc = highest.cc
Can anybody help me out?
Remove CC column from group by. Try this.
SELECT t.* FROM t
JOIN (
SELECT
t.id
,max(t.count) as max_slash24_count
FROM t
group by t.id
) highest
ON t.count = highest.max_slash24_count
and t.id= highest.id
Try this:
create table t (id varchar(10), cc varchar(10), count varchar(10))
insert into t (id,cc,count) values ('1','HN','22');
insert into t (id,cc,count) values ('1','US','18');
insert into t (id,cc,count) values ('1','VN','1');
insert into t (id,cc,count) values ('2','DK','2');
insert into t (id,cc,count) values ('2','US','256');
insert into t (id,cc,count) values ('3','SK','1');
insert into t (id,cc,count) values ('3','US','66310');
insert into t (id,cc,count) values ('4','UA','2');
insert into t (id,cc,count) values ('4','US','263');
insert into t (id,cc,count) values ('6','FR','7');
insert into t (id,cc,count) values ('6','US','84');
insert into t (id,cc,count) values ('9','BR','3');
select *
from t
where exists (
select *
from t as t1
group by t1.id
having t1.id = t.id and max(t1.count) = t.count
)
Result
ID CC COUNT
-------------
1 HN 22
2 US 256
3 US 66310
4 US 263
6 US 84
9 BR 3
Check SQLFiddle
This question was answered a lot of times on SO. The query is as simple as this:
SELECT m.id, m.cc, m.count
FROM t m # "m" from "max"
LEFT JOIN t b # "b" from "bigger"
ON m.id = b.id # match a row in "m" with a row in "b" by `id`
AND m.count < b.count # match only rows from "b" having bigger count
WHERE b.count IS NULL # there is no "bigger" count than "max"
The real issue on your question is about the column types. If count is char (and not int) then the string comparison happens using the dictionary order, not the numeric order.
For example, if the third row reads:
'1','VN','123'
you might expect it to be selected in the output, because 123 is bigger than 22. This does not happen because, as string, '123' is smaller than '22'.
Even tho, this was already answered, using ROW_NUMBER functionality as in SQL Server is quite fun and interesting: please look at this query:
SELECT TT.Id, TT.cc, TT.count
FROM (
SELECT t.cc
, t.count
, #row_number:=CASE WHEN #Id=Id THEN #row_number+1 ELSE 1 END AS row_number
, #Id:=Id AS Id
FROM t, (SELECT #row_number:=0, #Id:='') AS temp
ORDER BY t.Id, t.count DESC
) AS TT
WHERE TT.row_number = 1
ORDER BY TT.Id;
It produces expected output:
| Id | cc | count |
|----|----|-------|
| 1 | HN | 22 |
| 2 | US | 256 |
| 3 | US | 66310 |
| 4 | US | 263 |
| 6 | US | 84 |
| 9 | BR | 3 |
SQLFiddle
I've taken test data from #Andrey Morozov

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

Data structures available in 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)