如何在SQL中联接这3个表?

问题描述

我正在寻找正确的sql请求。我正在使用sqlite。

我有一个主表“ cmdb”:

name    | env  | type
-------------------------
VMV1    | Prod | Virtual
SP      | Dev  | Physical
VMO1    | Dev  | Virtual

我还有另一个表“ vmv”:

name  |    dns     | host  | management
---------------------------------------
VMV1  | VMV1.local | Host1 | Man1
VMV2  | VMV2.local | Host1 | Man1

还有另一个表“ vmo”:

name |    dns      | host  | management
---------------------------------------
VMO1  | VMO1.local | Host2 | Man2
VMO2  | VMO2.local | Host2 | Man2

这就是我想要得到的:

 name  | management |    dns     | env  | type
-------------------------------------------------
 VMV1  |    Man1    | VMV1.local | Prod | Virtual
 VMV2  |    Man1    | VMV2.local |      | 
 SP    |            |            | Dev  | Physical
 VMO1  |    Man2    | VMO1.local | Dev  | Virtual
 VMO2  |    Man2    | VMO2.local |      | 

但我无法获得正确的结果...

这就是让我最接近结果的原因。您可以看到,我在使sql请求比“ select * from table1”更加复杂方面并没有真正的优势。我尝试了很多组合,并在stackoverflow和其他有关UNION,JOIN等的网站上研究了很多示例sql关键字,但不幸的是我仍然没有得到它。这就是为什么我现在在这里寻求帮助。

SELECT
c.name,v.management,v.dns,c.env,c.type 
FROM cmdb AS c
LEFT JOIN vmv AS v ON v.name = c.name
LEFT JOIN vmo AS o ON o.name = c.name

我的结果是:

 name | management  |    dns     | env  | type
-----------------------------------------------
 VMV1 |    Man1     | VMV1.local | Prod | Virtual
 SP   |             |            | Dev  | Physical
 VMO1 |             | VMO1.local | Dev  | Virtual

解决方法

您可以使用LEFT进行联接,将3个表的所有不同名称与每个表联接:

select t.name,coalesce(v.management,o.management) management,coalesce(v.dns,o.dns) dns,c.env,c.type
from (
  select name from cmdb union
  select name from vmv union
  select name from vmo
) t
left join cmdb c on c.name = t.name
left join vmv v on v.name = t.name
left join vmo o on o.name = t.name

请参见demo

或者:

select t.name,n.management,n.dns,c.type
from (
  select name from cmdb union
  select name from vmv union
  select name from vmo
) t
left join cmdb c on c.name = t.name
left join (
  select name,dns,management from vmv
  union all
  select name,management from vmo
) n on n.name = t.name

请参见demo

结果:

| name | management | dns        | env  | type     |
| ---- | ---------- | ---------- | ---- | -------- |
| SP   |            |            | Dev  | Physical |
| VMO1 | Man2       | VMO1.local | Dev  | Virtual  |
| VMO2 | Man2       | VMO2.local |      |          |
| VMV1 | Man1       | VMV1.local | Prod | Virtual  |
| VMV2 | Man1       | VMV2.local |      |          |
,

原则上,您似乎要对UNIONvmovmv,然后对FULL OUTER JOIN做一个cmdb结果。我对sqlite并不熟悉,所以我不知道确切的语法是否可能与我为Oracle编写的语法不同(或者它甚至支持这些操作)。

这是我会尝试的:

SELECT NVL(cmdb.name,vm_all.name),management,env,type
 FROM
  cmdb
  FULL OUTER JOIN (
    SELECT name,dns FROM vmv
    UNION ALL
    SELECT name,dns FROM vmo
  ) vm_all
  ON vm_all.name = cmdb.name