递归SQL查询·
Recursive SQL Query·
我有以下关系:
公司信息(公司、角色、员工)
我想做的是找到两个员工之间最短的"path"。
例子
我需要找出乔和彼得之间的距离。
Joe 是 A 公司的首席执行官,名为 Alex 的人是董事会成员。
Alex是B公司的CEO,Peter是B公司的副总裁,那么Joe和Peter的距离就是2,如果Joe和Peter在同一家公司担任职务,就是1.
我需要使用递归 SQL 来解决这个问题。到目前为止,我已经想出了基本情况和最终的 select 字符串,但我终其一生都无法弄清楚递归部分。
WITH RECURSIVE shortest_path(c1,p1,c2,p2, path) AS (
-- Basecase --
SELECT c1.company, c1.person, c2.company, c2.person, array[c1.person, c2.person]
FROM CompanyInfo c1
INNER JOIN CompanyInfo c2 ON c1.company = c2.company
WHERE c1.person = 'Joe'
AND c1.person <> c2.person
UNION ALL
-- Recursive --
-- This is where I'm stuck.
)
SELECT p1, p2, array_length(path,1) -1 as distance
FROM shortest_path
WHERE p2 = 'Peter'
ORDER BY distance
LIMIT 1;
示例数据
CREATE TABLE CompanyInfo (
company text,
role text,
employee text,
primary key (company, role, employee)
);
insert into CompanyInfo values('Company A', 'CEO', 'Joe');
insert into CompanyInfo values('Company A', 'Board member', 'Alex');
insert into CompanyInfo values('Company B', 'CEO', 'Alex');
insert into CompanyInfo values('Company B', 'Board member', 'Peter');
预期输出
person 1 | person 2 | distance
Joe Peter 2
试试这个。保持 运行 直到可以将新员工添加到路径中。
CREATE TABLE CompanyInfo (
company text,
role text,
employee text,
primary key (company, role, employee)
);
insert into CompanyInfo values('Company A', 'CEO', 'Joe');
insert into CompanyInfo values('Company A', 'Board member', 'Alex');
insert into CompanyInfo values('Company B', 'CEO', 'Alex');
insert into CompanyInfo values('Company B', 'Board member', 'Peter');
WITH RECURSIVE shortest_path(c1,p1,c2,p2, path) AS (
-- Basecase --
SELECT c1.company, c1.employee, c2.company, c2.employee, array[c1.employee, c2.employee]
FROM CompanyInfo c1
JOIN CompanyInfo c2 ON c1.company = c2.company
AND c1.employee = 'Joe'
AND c1.employee <> c2.employee
UNION ALL
-- Recursive --
SELECT c1, p1, c3.company, c3.employee, path || c3.employee
FROM shortest_path c1
JOIN CompanyInfo c2 ON c1.p2 = c2.employee
JOIN CompanyInfo c3 ON c3.company = c2.company
AND NOT c3.employee = ANY (c1.path)
)
SELECT *, array_length(path,1) -1 as distance
FROM shortest_path
WHERE p2 = 'Peter'
ORDER BY distance
LIMIT 1;
我有以下关系:
公司信息(公司、角色、员工)
我想做的是找到两个员工之间最短的"path"。
例子
我需要找出乔和彼得之间的距离。 Joe 是 A 公司的首席执行官,名为 Alex 的人是董事会成员。 Alex是B公司的CEO,Peter是B公司的副总裁,那么Joe和Peter的距离就是2,如果Joe和Peter在同一家公司担任职务,就是1.
我需要使用递归 SQL 来解决这个问题。到目前为止,我已经想出了基本情况和最终的 select 字符串,但我终其一生都无法弄清楚递归部分。
WITH RECURSIVE shortest_path(c1,p1,c2,p2, path) AS (
-- Basecase --
SELECT c1.company, c1.person, c2.company, c2.person, array[c1.person, c2.person]
FROM CompanyInfo c1
INNER JOIN CompanyInfo c2 ON c1.company = c2.company
WHERE c1.person = 'Joe'
AND c1.person <> c2.person
UNION ALL
-- Recursive --
-- This is where I'm stuck.
)
SELECT p1, p2, array_length(path,1) -1 as distance
FROM shortest_path
WHERE p2 = 'Peter'
ORDER BY distance
LIMIT 1;
示例数据
CREATE TABLE CompanyInfo (
company text,
role text,
employee text,
primary key (company, role, employee)
);
insert into CompanyInfo values('Company A', 'CEO', 'Joe');
insert into CompanyInfo values('Company A', 'Board member', 'Alex');
insert into CompanyInfo values('Company B', 'CEO', 'Alex');
insert into CompanyInfo values('Company B', 'Board member', 'Peter');
预期输出
person 1 | person 2 | distance
Joe Peter 2
试试这个。保持 运行 直到可以将新员工添加到路径中。
CREATE TABLE CompanyInfo (
company text,
role text,
employee text,
primary key (company, role, employee)
);
insert into CompanyInfo values('Company A', 'CEO', 'Joe');
insert into CompanyInfo values('Company A', 'Board member', 'Alex');
insert into CompanyInfo values('Company B', 'CEO', 'Alex');
insert into CompanyInfo values('Company B', 'Board member', 'Peter');
WITH RECURSIVE shortest_path(c1,p1,c2,p2, path) AS (
-- Basecase --
SELECT c1.company, c1.employee, c2.company, c2.employee, array[c1.employee, c2.employee]
FROM CompanyInfo c1
JOIN CompanyInfo c2 ON c1.company = c2.company
AND c1.employee = 'Joe'
AND c1.employee <> c2.employee
UNION ALL
-- Recursive --
SELECT c1, p1, c3.company, c3.employee, path || c3.employee
FROM shortest_path c1
JOIN CompanyInfo c2 ON c1.p2 = c2.employee
JOIN CompanyInfo c3 ON c3.company = c2.company
AND NOT c3.employee = ANY (c1.path)
)
SELECT *, array_length(path,1) -1 as distance
FROM shortest_path
WHERE p2 = 'Peter'
ORDER BY distance
LIMIT 1;