SQL - 输出 2 个表的所有可能关系?
SQL - Output every possible relation of 2 tables?
对于标题含糊不清,我深表歉意。如果大家看完后有更好的建议我会修改的
我有 2 个 table:
DEPT table(部门):
|IDDEPT | DEPTNAME |
--------+------------+
| 10 | ACCOUNTING |
| 20 | RESEARCH |
| 30 | OPERATIONS |
--------+------------+
EMP table(员工):
| IDEMP | EMPNAME | MGR | IDDEPT |
--------+-----------+-------+--------+
| 7001 | SMITH | 7007 | 10 |
| 7002 | ALLEN | 7006 | 10 |
| 7003 | WARD | 7006 | 20 |
| 7004 | JONES | 7006 | 20 |
| 7005 | MARTIN | 7007 | 10 |
| 7006 | BLAKE | 7008 | 20 |
| 7007 | FORD | 7008 | 10 |
| 7008 | KING | NULL | 10 |
--------+-----------+-------+--------+
MGR 列是员工的经理标识符。 KING 有一个 NULL,因为他是公司的董事。 EMP 上的 IDDEPT table 是员工所属的部门。
我想做的是,对于每个经理(在这种情况下为 KING、FORD 和 BLAKE),显示他们在每个部门(10、20 和 30)监管的员工人数。
对于这个给定的场景,我试图获得的输出(严格来说不是这个顺序)如下:
| IDEMP | EMPNAME | IDDEPT | N_EMPLOYEES_SUPERVISED |
--------+-----------+--------+--------------------------+
| 7006 | BLAKE | 10 | 1 |
| 7006 | BLAKE | 20 | 2 |
| 7006 | BLAKE | 30 | 0 |
| 7007 | FORD | 10 | 2 |
| 7007 | FORD | 20 | 0 |
| 7007 | FORD | 30 | 0 |
| 7008 | KING | 10 | 1 |
| 7008 | KING | 20 | 1 |
| 7008 | KING | 30 | 0 |
--------+-----------+--------+--------------------------+
但是,我无法输出计数为 0 的行。
您可以 cross join
员工 table 与部门列表,然后将原始 table 带入 left join
。要将结果限制为经理员工,我们可以使用 exists
:
select m.idemp, m.empname, d.iddept,
count(e.idemp) as n_employees_supervised
from emp m
cross join dept d
left join emp e on e.mgr = m.idemp and e.iddept = d.iddept
where exists (select 1 from emp e1 where e1.mgr = m.idemp)
group by m.idemp, m.empname, d.iddept
避免 exists
子查询的替代方法是条件聚合:
select m.idemp, m.empname, d.iddept,
sum(case when e.iddept = d.iddept then 1 else 0 end) as n_employees_supervised
from emp m
cross join dept d
inner join emp e on e.mgr = m.idemp
group by m.idemp, m.empname, d.iddept
您可以使用分层查询来降低 EMP
层次结构 2 级,然后在 DEPT
table 上使用分区外部联接,然后再聚合(并且仅从 EMP
和 DEPT
各一次):
SELECT e.idemp,
e.empname,
d.iddept,
COUNT( e.iddept )
FROM DEPT d
LEFT OUTER JOIN (
SELECT CONNECT_BY_ROOT( IDEMP ) AS IDEMP,
CONNECT_BY_ROOT( EMPNAME ) AS EMPNAME,
IDDEPT
FROM EMP e
WHERE LEVEL = 2
CONNECT BY PRIOR IDEMP = MGR
) e
PARTITION BY ( e.IDEMP, e.EMPNAME )
ON ( e.IDDEPT = d.IDDEPT )
GROUP BY
e.idemp,
e.empname,
d.iddept;
其中,对于示例数据:
CREATE TABLE DEPT ( IDDEPT, DEPTNAME ) AS
SELECT 10, 'ACCOUNTING' FROM DUAL UNION ALL
SELECT 20, 'RESEARCH' FROM DUAL UNION ALL
SELECT 30, 'OPERATIONS' FROM DUAL;
CREATE TABLE EMP ( IDEMP, EMPNAME, MGR, IDDEPT ) AS
SELECT 7001, 'SMITH', 7007, 10 FROM DUAL UNION ALL
SELECT 7002, 'ALLEN', 7006, 10 FROM DUAL UNION ALL
SELECT 7003, 'WARD', 7006, 20 FROM DUAL UNION ALL
SELECT 7004, 'JONES', 7006, 20 FROM DUAL UNION ALL
SELECT 7005, 'MARTIN', 7007, 10 FROM DUAL UNION ALL
SELECT 7006, 'BLAKE', 7008, 20 FROM DUAL UNION ALL
SELECT 7007, 'FORD', 7008, 10 FROM DUAL UNION ALL
SELECT 7008, 'KING', NULL, 10 FROM DUAL;
输出:
IDEMP | EMPNAME | IDDEPT | COUNT(E.IDDEPT)
----: | :------ | -----: | --------------:
7006 | BLAKE | 10 | 1
7006 | BLAKE | 20 | 2
7006 | BLAKE | 30 | 0
7007 | FORD | 10 | 2
7007 | FORD | 20 | 0
7007 | FORD | 30 | 0
7008 | KING | 10 | 1
7008 | KING | 20 | 1
7008 | KING | 30 | 0
db<>fiddle here
对于标题含糊不清,我深表歉意。如果大家看完后有更好的建议我会修改的
我有 2 个 table:
DEPT table(部门):
|IDDEPT | DEPTNAME |
--------+------------+
| 10 | ACCOUNTING |
| 20 | RESEARCH |
| 30 | OPERATIONS |
--------+------------+
EMP table(员工):
| IDEMP | EMPNAME | MGR | IDDEPT |
--------+-----------+-------+--------+
| 7001 | SMITH | 7007 | 10 |
| 7002 | ALLEN | 7006 | 10 |
| 7003 | WARD | 7006 | 20 |
| 7004 | JONES | 7006 | 20 |
| 7005 | MARTIN | 7007 | 10 |
| 7006 | BLAKE | 7008 | 20 |
| 7007 | FORD | 7008 | 10 |
| 7008 | KING | NULL | 10 |
--------+-----------+-------+--------+
MGR 列是员工的经理标识符。 KING 有一个 NULL,因为他是公司的董事。 EMP 上的 IDDEPT table 是员工所属的部门。
我想做的是,对于每个经理(在这种情况下为 KING、FORD 和 BLAKE),显示他们在每个部门(10、20 和 30)监管的员工人数。
对于这个给定的场景,我试图获得的输出(严格来说不是这个顺序)如下:
| IDEMP | EMPNAME | IDDEPT | N_EMPLOYEES_SUPERVISED |
--------+-----------+--------+--------------------------+
| 7006 | BLAKE | 10 | 1 |
| 7006 | BLAKE | 20 | 2 |
| 7006 | BLAKE | 30 | 0 |
| 7007 | FORD | 10 | 2 |
| 7007 | FORD | 20 | 0 |
| 7007 | FORD | 30 | 0 |
| 7008 | KING | 10 | 1 |
| 7008 | KING | 20 | 1 |
| 7008 | KING | 30 | 0 |
--------+-----------+--------+--------------------------+
但是,我无法输出计数为 0 的行。
您可以 cross join
员工 table 与部门列表,然后将原始 table 带入 left join
。要将结果限制为经理员工,我们可以使用 exists
:
select m.idemp, m.empname, d.iddept,
count(e.idemp) as n_employees_supervised
from emp m
cross join dept d
left join emp e on e.mgr = m.idemp and e.iddept = d.iddept
where exists (select 1 from emp e1 where e1.mgr = m.idemp)
group by m.idemp, m.empname, d.iddept
避免 exists
子查询的替代方法是条件聚合:
select m.idemp, m.empname, d.iddept,
sum(case when e.iddept = d.iddept then 1 else 0 end) as n_employees_supervised
from emp m
cross join dept d
inner join emp e on e.mgr = m.idemp
group by m.idemp, m.empname, d.iddept
您可以使用分层查询来降低 EMP
层次结构 2 级,然后在 DEPT
table 上使用分区外部联接,然后再聚合(并且仅从 EMP
和 DEPT
各一次):
SELECT e.idemp,
e.empname,
d.iddept,
COUNT( e.iddept )
FROM DEPT d
LEFT OUTER JOIN (
SELECT CONNECT_BY_ROOT( IDEMP ) AS IDEMP,
CONNECT_BY_ROOT( EMPNAME ) AS EMPNAME,
IDDEPT
FROM EMP e
WHERE LEVEL = 2
CONNECT BY PRIOR IDEMP = MGR
) e
PARTITION BY ( e.IDEMP, e.EMPNAME )
ON ( e.IDDEPT = d.IDDEPT )
GROUP BY
e.idemp,
e.empname,
d.iddept;
其中,对于示例数据:
CREATE TABLE DEPT ( IDDEPT, DEPTNAME ) AS
SELECT 10, 'ACCOUNTING' FROM DUAL UNION ALL
SELECT 20, 'RESEARCH' FROM DUAL UNION ALL
SELECT 30, 'OPERATIONS' FROM DUAL;
CREATE TABLE EMP ( IDEMP, EMPNAME, MGR, IDDEPT ) AS
SELECT 7001, 'SMITH', 7007, 10 FROM DUAL UNION ALL
SELECT 7002, 'ALLEN', 7006, 10 FROM DUAL UNION ALL
SELECT 7003, 'WARD', 7006, 20 FROM DUAL UNION ALL
SELECT 7004, 'JONES', 7006, 20 FROM DUAL UNION ALL
SELECT 7005, 'MARTIN', 7007, 10 FROM DUAL UNION ALL
SELECT 7006, 'BLAKE', 7008, 20 FROM DUAL UNION ALL
SELECT 7007, 'FORD', 7008, 10 FROM DUAL UNION ALL
SELECT 7008, 'KING', NULL, 10 FROM DUAL;
输出:
IDEMP | EMPNAME | IDDEPT | COUNT(E.IDDEPT) ----: | :------ | -----: | --------------: 7006 | BLAKE | 10 | 1 7006 | BLAKE | 20 | 2 7006 | BLAKE | 30 | 0 7007 | FORD | 10 | 2 7007 | FORD | 20 | 0 7007 | FORD | 30 | 0 7008 | KING | 10 | 1 7008 | KING | 20 | 1 7008 | KING | 30 | 0
db<>fiddle here