SQL - 在任意级别加入树时是否有推荐的方法?
SQL - is there a recommended approach when joining to a tree at an arbitrary level?
感谢阅读。我确信有一种明智的方法可以做我想做的事情,但我缺乏数据库经验让我失望。
我将大大简化以指出我的问题.....我有 3 tables
- a table 呼叫了员工(employee_id、姓名、parent_id 等)。
- 一个 table 调用的项目(project_id、project_name 等)
- 一个table链接两个叫做assigned_projects(id,employee_id,project_id)
员工 table 最多 6 层(尽管在某些地方可能浅至 3 层)并包含大约 900 名员工。例如
A
/ \
B C
/|\
D E F
现在,可以在任何级别分配项目。如果我将它分配给员工 A,那么它也应该链接到他的所有下属 (B->F)。如果我把它分配给C,那么它应该链接到D+E+F,但我也想看到它在A的职权范围内。
当我调出员工的个人资料时,我正在使用锚定在适当员工身上的 CTE 来递归查找所有下属。我的问题是,对于这些下属中的每一个,我如何加入 assigned_projects table 以查看此人的职权范围内有哪些项目?
我考虑的选项:
- 先做 CTE 部分,然后在 php 中迭代所有 employee_id 到 运行 从 [=51] 中提取 project_id 的单独查询=] table
- 最初将项目分配给员工时,遍历树并为每个合适的员工向 assigned_projects 添加一个条目。这里的问题是,如果员工在树周围移动(换工作),我希望他们相应地 inherit/remove 项目。
明确地说,在调出 C 的配置文件时,我希望看到分配给 A、C、D、E、F 的所有项目。在调出 B 的个人资料时,我希望看到与 A 或 B 相关的所有项目。
似乎在 SQL 中应该有一种方法可以使用一些我只是没有经验的聪明才智来做到这一点?或者我应该改变我的 table 结构....我也对此持开放态度。
希望我解释得当。感谢您的帮助,感谢您的宝贵时间。
我认为你可能为自己创造了一个充满伤害的世界。这种树表示形式的问题是您将以某种形式的递归结束以实现您的目标。性能可能会很糟糕,并且更改会很复杂。我建议您阅读 http://ebooks.cawok.pro/Morgan.Kaufmann.Joe.Celkos.Trees.and.Hierarchies.in.SQL.for.Smarties.May.2004.eBook-DDU.pdf 以获得更好的选择。
它并非没有令人头疼的问题。您确实需要用于 INSERT 和 DELETE 操作的存储过程,但是一旦设置了嵌套集模型树,您所谈论的操作就会简单得多。要找到您想要的数据,您只需将树 table 加入项目 table 并查询分配的员工的左值和右值介于经理的左值和右值之间的所有项目。要根据经理分配给员工,您需要查找 MAX(leftvalue) < 员工的 leftvalue 和 MIN(rightvalue) > 员工的 rightvalue 的节点。
IF OBJECT_ID('tempdb..#tree') IS NOT NULL
DROP TABLE #tree
create table #tree (emp varchar(10), lval int, rval int)
INSERT INTO #tree
SELECT 'Bob',1,12
UNION
SELECT 'Harry',2,5
UNION
SELECT 'Barry',6,11
UNION
SELECT 'Dave',3,4
UNION
SELECT 'Mavis',7,8
UNION
SELECT 'Maud',9,10
IF OBJECT_ID('tempdb..#Projects') IS NOT NULL
DROP TABLE #Projects
CREATE TABLE #Projects(projectid INT,projectname VARCHAR(20))
INSERT INTO #Projects
SELECT 1,'Project Mammoth'
UNION
SELECT 2,'Project Minnow'
UNION
SELECT 3,'Project medium'
IF OBJECT_ID('tempdb..#ProjectReleations') IS NOT NULL
DROP TABLE #ProjectRelations
CREATE TABLE #ProjectRelations(emp VARCHAR(10),projectid INT)
INSERT INTO #ProjectRelations
SELECT 'Barry',1
UNION
SELECT 'Maud',2
UNION
SELECT 'Dave',3
--Find Mavis' immediate manager (Barry)
SELECT
*
FROM
#tree
LEFT JOIN
#ProjectRelations ON
#tree.emp=#Projectrelations.emp
LEFT JOIN
#Projects ON
#Projectrelations.projectid=#Projects.projectid
WHERE
#tree.lval=(
SELECT
MAX(tree.lval)
FROM
#tree
inner join
#tree as tree ON
tree.lval < #tree.lval
AND
tree.rval > #tree.rval
WHERE
#tree.emp='Mavis'
)
--Find all projects under a particular employee (including projects assigned to that employee). If you want only projects assigned to subordinates use #tree.lval > rather than #tree.lval >=
SELECT
*
FROM
#tree
INNER JOIN
#ProjectRelations ON
#tree.emp=#Projectrelations.emp
INNER JOIN
#Projects ON
#Projectrelations.projectid=#Projects.projectid
WHERE
#tree.lval >= (
SELECT
lval
FROM
#tree
WHERE
#tree.emp='Bob'
)
我不知道这是否有帮助,但是树在 SQL 中是一种痛苦,我个人的感觉是,在各种邪恶中,嵌套集不那么可怕。
感谢阅读。我确信有一种明智的方法可以做我想做的事情,但我缺乏数据库经验让我失望。
我将大大简化以指出我的问题.....我有 3 tables
- a table 呼叫了员工(employee_id、姓名、parent_id 等)。
- 一个 table 调用的项目(project_id、project_name 等)
- 一个table链接两个叫做assigned_projects(id,employee_id,project_id)
员工 table 最多 6 层(尽管在某些地方可能浅至 3 层)并包含大约 900 名员工。例如
A
/ \
B C
/|\
D E F
现在,可以在任何级别分配项目。如果我将它分配给员工 A,那么它也应该链接到他的所有下属 (B->F)。如果我把它分配给C,那么它应该链接到D+E+F,但我也想看到它在A的职权范围内。
当我调出员工的个人资料时,我正在使用锚定在适当员工身上的 CTE 来递归查找所有下属。我的问题是,对于这些下属中的每一个,我如何加入 assigned_projects table 以查看此人的职权范围内有哪些项目?
我考虑的选项:
- 先做 CTE 部分,然后在 php 中迭代所有 employee_id 到 运行 从 [=51] 中提取 project_id 的单独查询=] table
- 最初将项目分配给员工时,遍历树并为每个合适的员工向 assigned_projects 添加一个条目。这里的问题是,如果员工在树周围移动(换工作),我希望他们相应地 inherit/remove 项目。
明确地说,在调出 C 的配置文件时,我希望看到分配给 A、C、D、E、F 的所有项目。在调出 B 的个人资料时,我希望看到与 A 或 B 相关的所有项目。
似乎在 SQL 中应该有一种方法可以使用一些我只是没有经验的聪明才智来做到这一点?或者我应该改变我的 table 结构....我也对此持开放态度。
希望我解释得当。感谢您的帮助,感谢您的宝贵时间。
我认为你可能为自己创造了一个充满伤害的世界。这种树表示形式的问题是您将以某种形式的递归结束以实现您的目标。性能可能会很糟糕,并且更改会很复杂。我建议您阅读 http://ebooks.cawok.pro/Morgan.Kaufmann.Joe.Celkos.Trees.and.Hierarchies.in.SQL.for.Smarties.May.2004.eBook-DDU.pdf 以获得更好的选择。
它并非没有令人头疼的问题。您确实需要用于 INSERT 和 DELETE 操作的存储过程,但是一旦设置了嵌套集模型树,您所谈论的操作就会简单得多。要找到您想要的数据,您只需将树 table 加入项目 table 并查询分配的员工的左值和右值介于经理的左值和右值之间的所有项目。要根据经理分配给员工,您需要查找 MAX(leftvalue) < 员工的 leftvalue 和 MIN(rightvalue) > 员工的 rightvalue 的节点。
IF OBJECT_ID('tempdb..#tree') IS NOT NULL
DROP TABLE #tree
create table #tree (emp varchar(10), lval int, rval int)
INSERT INTO #tree
SELECT 'Bob',1,12
UNION
SELECT 'Harry',2,5
UNION
SELECT 'Barry',6,11
UNION
SELECT 'Dave',3,4
UNION
SELECT 'Mavis',7,8
UNION
SELECT 'Maud',9,10
IF OBJECT_ID('tempdb..#Projects') IS NOT NULL
DROP TABLE #Projects
CREATE TABLE #Projects(projectid INT,projectname VARCHAR(20))
INSERT INTO #Projects
SELECT 1,'Project Mammoth'
UNION
SELECT 2,'Project Minnow'
UNION
SELECT 3,'Project medium'
IF OBJECT_ID('tempdb..#ProjectReleations') IS NOT NULL
DROP TABLE #ProjectRelations
CREATE TABLE #ProjectRelations(emp VARCHAR(10),projectid INT)
INSERT INTO #ProjectRelations
SELECT 'Barry',1
UNION
SELECT 'Maud',2
UNION
SELECT 'Dave',3
--Find Mavis' immediate manager (Barry)
SELECT
*
FROM
#tree
LEFT JOIN
#ProjectRelations ON
#tree.emp=#Projectrelations.emp
LEFT JOIN
#Projects ON
#Projectrelations.projectid=#Projects.projectid
WHERE
#tree.lval=(
SELECT
MAX(tree.lval)
FROM
#tree
inner join
#tree as tree ON
tree.lval < #tree.lval
AND
tree.rval > #tree.rval
WHERE
#tree.emp='Mavis'
)
--Find all projects under a particular employee (including projects assigned to that employee). If you want only projects assigned to subordinates use #tree.lval > rather than #tree.lval >=
SELECT
*
FROM
#tree
INNER JOIN
#ProjectRelations ON
#tree.emp=#Projectrelations.emp
INNER JOIN
#Projects ON
#Projectrelations.projectid=#Projects.projectid
WHERE
#tree.lval >= (
SELECT
lval
FROM
#tree
WHERE
#tree.emp='Bob'
)
我不知道这是否有帮助,但是树在 SQL 中是一种痛苦,我个人的感觉是,在各种邪恶中,嵌套集不那么可怕。