0

I have a SQL query that finds the "departments" the specified person has access to.

And some departments are subdepartments of others, so when the person has acces to a department he has also access to all of his subdepartments.

This works because in the departments table, every department has a name and ID and a "fatherID" which specifies what department is his father department.

But it is also possible that this nests even further and i found no way to show the names of all departments below 1 level of subdepartments.

SELECT B.DepartmentDesc FROM  CompanyDepartmentPermission A 
INNER JOIN CompanyDepartment] B 
ON A.DepartmentID=B.DepartmentID 
OR A.DepartmentID=B.FatherDepartmentID 
WHERE A.PEmplID = 68

This is possible. I get all the names from the department and all his subdepartments:

enter image description here

But in this case i get every subdepartment, except the on nested a level lower.

enter image description here

My goal is to be able to recursively also show all nested subdepartments. And i HAVE to do this in only 1 query. As i am very inexperienced and have not much insight in nested querys i have not found a way to solve this. I hope someone can give me a nudge to the right direction.

PS: The pictures where from a C# program i made where i made it work and this is just for clarification how it looks. And i hope i could explain what i want. Otherwise let me know and i will try to rephrase this :)

EDIT: This is de structure of the two tables. Thanks Akaino for pointing out

enter image description here

SOLUTION: Sadly none of the asnwers here helped me, but instead a halfway similar question here on SO. The WITH UNION statements helped me a lot. This is The working query for my problem.

WITH DepartmentHirarchy AS
(
SELECT B.DepartmentID,DepartmentDesc,FatherDepartmentID, DepartmentResponsiblePEmplID
FROM CompanyDepartment AS B
INNER JOIN CompanyDepartmentPermission AS A ON A.DepartmentID=B.DepartmentID
WHERE A.PEmplID= 34 OR DepartmentResponsiblePEmplID = 34
UNION ALL
SELECT  nextLevel.DepartmentID,nextLevel.DepartmentDesc,nextLevel.FatherDepartmentID, nextLevel.DepartmentResponsiblePEmplID
FROM DepartmentHirarchy AS recCall
INNER JOIN CompanyDepartment AS nextLevel ON nextLevel.FatherDepartmentID=recCall.DepartmentID
)
SELECT * FROM DepartmentHirarchy
ORDER BY FatherDepartmentID,DepartmentID
GO
MansNotHot
  • 263
  • 1
  • 3
  • 19
  • 2
    Select all departments from database and organize them with C# – selami Jan 09 '18 at 12:49
  • @selami i sadly cannot use c# and i have to use 1 query. This is a task that was given to me by my boss for a specific use – MansNotHot Jan 09 '18 at 12:51
  • That's horrible design though. Without knowing how 'deep' you need to nest your query, there is little chance accomplishing this with pure sql. Do you have a database schema? Possibly there is another, more convenient approach. – Akaino Jan 09 '18 at 12:53
  • @akaino i will update the question – MansNotHot Jan 09 '18 at 12:56
  • @akaino As far as i know my boss wants this single query to be able to copy paste it for some use. He is a programmer for several years so i suppose that it is possible to do so when he asks for it :) – MansNotHot Jan 09 '18 at 12:59
  • Which DBMS are you using? SQL dialects differ. What you're looking for is frequently called a ["bill of materials" query](https://stackoverflow.com/questions/18426812/recursive-query-for-bill-of-materials). – mustaccio Jan 09 '18 at 13:05
  • Sure thing! I didn't want to question his skills ;). It's just hard to figure without knowing the dependencies. From what I can see here, there seems to be no 'third' child department. So, test doesn't have any children. Is that right? If so, your approach is ok. If test had a child department, you'd need to join departments again. Just like you did already. See @Pradip's answer. You might also want to check [this link](https://stackoverflow.com/questions/1757260/simplest-way-to-do-a-recursive-self-join) – Akaino Jan 09 '18 at 13:06
  • @Akaino This is just an example i made. test "could" have one or several child departments. The query will have to be able to recursively show all departments unimportant how far they are nested and in what order. It does not have to show the names in any specific order, I just want a list of departments one person is allowed to acces in no particular order or shown hirarchy – MansNotHot Jan 09 '18 at 13:09
  • Thats not a horrible design. That's a standard self referencing hierarchy table. I will edit your question and tag it as SQL Server since your screenshots appear to show that. – Nick.Mc Jan 09 '18 at 13:17
  • @Nick.McDermaid Thanks – MansNotHot Jan 09 '18 at 13:20

2 Answers2

2

For parent/child tree hierarchy, try the following SQL code.

I assume, your table name is Departments. You can change the table name in the following SQL.

I works with SQL Server.

WITH RELATION (DepartmentID, FatherDepartmentID, DepartmentDesc, [Level], [Order])
AS
(
    SELECT DepartmentID, FatherDepartmentID, DepartmentDesc, 0, CAST(DepartmentID AS VARCHAR(200))
    FROM Departments
    WHERE FatherDepartmentID IS NULL
    UNION ALL
    SELECT P.DepartmentID, P.FatherDepartmentID, P.DepartmentDesc, R.[Level]+1, CAST(R.[Order] + '_' + CAST(p.DepartmentID AS VARCHAR(200)) AS VARCHAR(200))  
    FROM Departments P
    JOIN RELATION R ON P.FatherDepartmentID = R.DepartmentID
)
SELECT RIGHT('----------', ([Level]*3)) + DepartmentDesc  
FROM RELATION R
JOIN CompanyDepartment D ON D.DepartmentID = R.DepartmentID 
WHERE PEmplID= 68
ORDER BY R.[ORDER]
selami
  • 2,478
  • 1
  • 21
  • 25
  • I just tried to understand your query, but one thing i cant wrap my head around is where is the other table? somehow the permissions table is not in the query so "PEmplID" which is part of the permissions table is not working. – MansNotHot Jan 09 '18 at 13:13
  • It's just another join exactly how you did it in your first sample query. This is the standard way to traverse a self referencing table of unknown depth. You should definitely pursue this solution. None of the other solutions will go to the bottom of the tree. This one will, not matter how deep it is. – Nick.Mc Jan 09 '18 at 13:17
  • @Nick.McDermaid Yeah looks good but i cannot figure out where the second table is referenced. He is referencing the departments table 2 times but not the permissions table. :/ – MansNotHot Jan 09 '18 at 13:20
  • See the `FROM RELATION` line right down the bottom? You join that like tihs: `FROM RELATION INNER JOIN CompanyDepartmentPermission ON` _your join condition_ – Nick.Mc Jan 09 '18 at 13:21
  • @MansNotHot in your question, there is an extra ']' character in "CompanyDepartment] B " Is there two table? Or just one table? – selami Jan 09 '18 at 13:22
  • @selami Yes there are two. CompanyDepartment and CompanyDepartmentPermissions. The ] character was just a typo. In the last scree nshot you can see, permissions is the table below, and department is the table above – MansNotHot Jan 09 '18 at 13:23
  • @selami and PEmpl is part of the Permissions table. And because it is not referenced it is not found when i try to apply it – MansNotHot Jan 09 '18 at 13:25
  • @selami And it would be really awesome if you could explain roughly what the query does and how so i can understand it. I want to understand querys better :) – MansNotHot Jan 09 '18 at 13:28
  • @selami Yes i have seen it and tried it out, but it only returns me the most top departments, none that are below them. – MansNotHot Jan 09 '18 at 13:37
  • Did it work before the additional join? Are there permissions defined for children departments (i.e. for department 21)? if there are no permissions defined you need to use an outer join. This query is called a CTE or common table expression and there are many online explanations for that. – Nick.Mc Jan 09 '18 at 23:22
-1

It seems like you want to do an hierarchy search. If your server supports the use of the hierarchy datatype (if not, you might want to consider it if you are planning to use a lot of hierachy searches) you could try and use the isDescendantOf method.

Example

DECLARE @parent hierarchyid
SELECT @parent = B.DepartmentDesc
FROM CompanyDepartment B 
Where B.DepartmentDesc = 'Name your deparment'

SELECT *  
FROM CompanyDepartment 
WHERE DepartmentDesc.IsDescendantOf(@parent) = 1 ; 
ppijnenburg
  • 153
  • 1
  • 12